2016-05-31 15 views
7

Mam aplikację, którą rozwijam w Angular 2 (RC1). Menu należy utworzyć z bazy danych. Dane są dostarczane za pośrednictwem Web Api w formularzu JSON. Chciałbym zbudować menu z danych rekurencyjnie, aby mieć pewność, że głębia menu nie jest problemem.Styl w pętli ngFor

Problem polega na tym, że chcę dodać klasę do określonego wiersza pętli ngFor, a klasa zostanie dodana do wszystkich wierszy, a nie tylko do jednego.

Kod szuka coś takiego:

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> 

Więc, gdy klikam na rodzica wszyscy rodzice stają się aktywne, nie tylko, że zwłaszcza jeden, co będzie satysfakcjonujące zachowanie. Co robię źle?

+0

Co masz na myśli przez „kliknięcie na rodzica wszystkich rodziców stać aktywny"? Czy powinno to być "kliknij na rodzica wszystkie" MenuComponent "stają się aktywne"? –

+0

Po zbudowaniu menu daje hierarchię elementów nadrzędnych i podrzędnych. Załóżmy, że model dla menu to: 'id: number; parentId: number; name: string; dzieci: IMenu []; '. Kiedy klikam na instancję nadrzędną elementu menu, otwieram wszystkie wystąpienia menu nadrzędnego. Wymagane zachowanie powinno polegać na tym, że gdy kliknę na instancję nadrzędną, otworzy się lub powiesz, aby podać poprawną klasę tylko do blokowania z dziećmi wybranego rodzica. –

Odpowiedz

10

Wydaje się, że zmienna isSelected jest wspólna całej listy. Zmień zmienną, aby śledzić indeks.

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; 
    } 
} 

czyni go

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

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

+0

Dzięki, właśnie tego chcę. –

+0

Dzięki pracy jak w niebie :) –

+0

Działa jak urok! Niezła odpowiedź! – fauverism

3

Istnieje kilka zbędnych '. Chyba chcesz powiązać wartość rzeczowych isSelected nie napisu 'isSelected' (sam z frst)

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

Dzięki, ale spróbowałem bez '' 'z tym samym wynikiem. Ciągle koduję z '' ', ponieważ daje mi to możliwość dołączenia innych logicznych pytań, takich jak:' [ngClass] = "{'nav-stacked': 'item.depth === 1'}" '. –

+1

Dlaczego to powinno lepiej działać z '' 'niż bez? –

+0

Ta szczególna składnia ('[ngClass] =" {'nav-stacked': item.depth === 1} "') nie działa. –

2

mam rozwiązanie (i jest to łatwe), po otrzymaniu danych JSON i zapisać go w zmiennej Twój (w twoim przypadku nazywa się menu) dodaj do menu nowe pole zwane klasami i wyrenderuj je w szablonie!

Przykład:

@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 
    } 
    } 
} 

i w szablonie można uczynić go 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

Dzięki! Spróbuję na pewno. Wciąż będę szukał odpowiedzi, ale nie po to, by jeszcze raz przepuścić przez tablicę. –

+0

@ IgorIlić odpowiedź *** zaclerv ***, że ** zweryfikowany ** jest świetny, ale działa tylko na kliknięcie! moja odpowiedź doda klasę do wielu elementów i bez zdarzenia kliknięcia, to jest różnica! w każdym razie powodzenia kolego :) –

0

Dodaj #clickState do wiersza w *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>