Style in ngFor loop

I have an application that I am developing in Angular 2 (RC1). The menu must be created from the database. Data is delivered via Web Api in JSON form. I would like to create a menu from the data recursively to be sure that the depth of the menu is not a problem.

The problem is that I want to add the class to a specific line of the ngFor loop, and the class is added to all the lines, not just the one I want.

The code looks something like this:

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> 

So, when I click on the parent, all the parents become active, and not just what will be, which will be a satisfactory behavior. What am I doing wrong?

+7
angular
source share
4 answers

It seems your isSelected variable is being shared across the entire list. Change the variable to track the index.

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

visualize it with

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

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

+10
source share

There are some redundant ones. ' I think you want to associate the value of the isSelected property not with the string 'isSelected' (same as frst )

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

I have a solution (and this is easy), when you get JSON data and save it in your variable (in your case it is called menu ) add in t20> a new field called classes and display it in the template!

Example:

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

and in the template you can make it 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> 
+2
source share

Add #clickState to your line in *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> 
0
source share

All Articles