Style in ngFor loop

2020-08-17 07:57发布

I have an app which I'm developing in Angular 2 (RC1). The menu is need to be created from the database. Data is delivered via Web Api in JSON form. I would like to build menu from the data recursively, to be sure that depth of the menu is not an issue.

The problem is when I'm want to add class on particular row of ngFor loop, and the class is added to all rows instead of just one I want to.

The code is looking 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 parent all parents become active, not only that particular one, what will be satisfying behaviour. What I do wrong?

标签: angular
4条回答
Summer. ? 凉城
2楼-- · 2020-08-17 08:09

I got a solution (and it's easy), when you receive the JSON data and save it in a variable of yours (in your case its called menu) add to menu a new field called classes and render 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 render 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>
查看更多
Melony?
3楼-- · 2020-08-17 08:10

It seems like your variable isSelected is shared across the list. Change the variable to track the index instead.

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

render 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>

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

查看更多
爷的心禁止访问
4楼-- · 2020-08-17 08:13

Add #clickState to your row in the *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>
查看更多
神经病院院长
5楼-- · 2020-08-17 08:23

There are some redundant '. I guess you want to bind the value of the property isSelected not the 'isSelected' string (same with frst)

 <li  *ngFor="let item of menu; let frst=first"
       class="menu-list" 
       [ngClass]="{'active': isSelected, 'active': frst}">
查看更多
登录 后发表回答