2016-05-31 26 views
7

Ho un'app che sto sviluppando in Angular 2 (RC1). Il menu deve essere creato dal database. I dati vengono consegnati tramite Web Api in formato JSON. Mi piacerebbe costruire il menu dai dati in modo ricorsivo, per essere sicuro che la profondità del menu non sia un problema.Stile in ngPer loop

Il problema si verifica quando desidero aggiungere una classe su una particolare riga del ciclo ngFor e la classe viene aggiunta a tutte le righe anziché una sola a cui desidero.

Il codice sta cercando qualcosa di simile:

sidenav.component.ts

import { Component, Input } from '@angular/core'; 
import { IMenu } from '../../../shared/models/menu.interface'; 
import { MenuComponent } from './menu.component'; 

@Component({ 
    moduleId: module.id, 
    selector: 'sidenav', 
    templateUrl: 'sidenav.component.html', 
    directives: [MenuComponent] 
}) 
export class SidenavComponent { 
    @Input() menu: IMeni[] 
} 

sidenav.component.html

... 
<menu-view [menu]="menu"></menu-view> 
... 

menu.component.ts

import { Component, Input } from '@angular/core'; 
import { IMenu } from '../../../shared/models/menu.interface'; 
@Component({ 
    moduleId: module.id, 
    selector: 'menu-view', 
    templateUrl: 'menu.component.html', 
    directives: [MenuComponent] 
}) 
export class MenuComponent { 
    isSelected: boolean = false; 
    @Input() meni: IMeni[]; 

    onSelect(): void { 
     this.isSelected = !this.isSelected; 
    } 
} 

menu.component.html

<ul> 
    <li *ngFor="let item of menu; let frst=first" 
      class="menu-list" 
      [ngClass]="{'active': 'isSelected', 'active': 'frst'}"> 

     <a [routerLink]="[item.uri]" (click)="onSelect()" > {{item.name}}</a> 

     <meni-view [menu]="item.children"></meni-view> 

    </li> 
</ul> 

Così, quando clicco su genitore tutti i genitori diventano attive, non solo quel particolare uno, quello che sarà il comportamento soddisfacente. Cosa faccio di sbagliato?

+0

Che cosa si intende per "cliccare sul genitore tutti i genitori diventano attivo"? Se questo è "clicca su genitore tutti i" MenuComponent "diventano attivi"? –

+0

Quando il menu è creato, fornisce una gerarchia di elementi padre e figlio. Diciamo che il modello per il menu è: 'id: numero; parentId: numero; nome: stringa; bambini: IMenu []; '. Quindi, quando faccio clic sull'istanza genitore della voce di menu, apro tutte le istanze dei menu principali. Il comportamento voluto dovrebbe essere quello in cui clicco su istanza genitore, si aprirà, o per dire dare la classe corretta solo per bloccare con figli del genitore selezionato. –

risposta

10

Sembra che la variabile isSelected è condivisa in tutto l'elenco. Cambia la variabile per tenere traccia dell'indice.

export class App { 
    menu = [{name: "Item 1", url: "/item1"}, {name: "Item 2", url: "/item2"},{name: "Item 3", url: "/item3"}]; 
    selectedIdx = 0; 

    selectItem(index):void { 
     this.selectedIdx = index; 
    } 
} 

renderlo con

<li *ngFor="let item of menu;let i = index" 
    class="menu-list" [ngClass]="{'active': selectedIdx == i}"> 
    <a (click)="selectItem(i)"> {{item.name}}</a> 
</li> 

Lavorare http://plnkr.co/edit/7aDLNnhS8MQ1mJVfhGRR

+0

Grazie, è esattamente quello che voglio. –

+0

Grazie del lavoro come il paradiso :) –

+0

Funziona come un fascino! Bella risposta! – fauverism

3

Ci sono alcuni ridondanti '. Credo che si desidera associare il valore della proprietà isSelected non la stringa 'isSelected' (stesso con frst)

<li *ngFor="let item of menu; let frst=first" 
     class="menu-list" 
     [ngClass]="{'active': isSelected, 'active': frst}"> 
+0

Grazie, ma ho provato senza "" con lo stesso risultato. Continuo a programmare con ''' perché mi dà la possibilità di includere altre domande logiche, come:' [ngClass] = "{'nav-stacked': 'item.depth === 1'}" '. –

+1

Perché dovrebbe funzionare meglio con "" piuttosto che senza? –

+0

Quella particolare sintassi ('[ngClass] =" {'nav-stacked': item.depth === 1} "') non funziona. –

2

ho ottenuto una soluzione (ed è facile), quando si ricevono i dati JSON e salvarlo in una variabile del tuo (nel tuo caso è chiamato menu) aggiungi a menu un nuovo campo chiamato classi e renderlo nel modello!

Esempio:

@Input() menu: IMenu[]; 
getMenu(){ 
    this.http.get(url).then(data => { 
    this.menu = data; 
    for(let i = 0; i < this.menu.length; i++) { 
     if(i == indexOfWantedElement){ 
     this.menu[i].classes = "myClass"; 
     continue; 
     } 
     this.menu[i].classes = ""; // others will have no classes 
    } 
    } 
} 

e nel modello si può renderlo easliy

<ul> 
    <li *ngFor="let item of menu;" class="menu-list {{ item.classes }}"> 
    <a [routerLink]="[item.uri]" (click)="onSelect()" >{{item.name}}</a> 
    <meni-view [menu]="item.children"></meni-view> 
    </li> 
</ul> 
+0

Grazie! Ci proverò di sicuro. Cercherò comunque la risposta senza fare altro ancora una volta attraverso l'array. –

+0

@ IgorIlić la risposta di *** zaclerv *** che hai ** verificato ** è ottimo ma funziona solo su click! la mia risposta aggiungerà la classe a più elementi e senza l'evento click, questa è la diffrence! comunque buona fortuna fella :) –

0

Aggiungi #clickState alla riga della *ngFor

<row #clickState> 
    <i class="icon-cloud-download" 
     *ngIf="!clickState.clicked" 
     (click)="clickState.clicked=true"></i> 
    <i class="fa fa-spinner" 
     *ngIf="clickState.clicked 
     (click)="clickState.clicked=false"></i> 
</row>