我在尝试在同一个元素上使用Angular的*ngFor和*ngIf时遇到了一个问题。

当试图在*ngFor中循环该集合时,该集合被视为null,因此当试图在模板中访问其属性时失败。

@Component({
  selector: 'shell',
  template: `
    <h3>Shell</h3><button (click)="toggle()">Toggle!</button>

    <div *ngIf="show" *ngFor="let thing of stuff">
      {{log(thing)}}
      <span>{{thing.name}}</span>
    </div>
  `
})

export class ShellComponent implements OnInit {

  public stuff:any[] = [];
  public show:boolean = false;

  constructor() {}

  ngOnInit() {
    this.stuff = [
      { name: 'abc', id: 1 },
      { name: 'huo', id: 2 },
      { name: 'bar', id: 3 },
      { name: 'foo', id: 4 },
      { name: 'thing', id: 5 },
      { name: 'other', id: 6 },
    ]
  }

  toggle() {
    this.show = !this.show;
  }

  log(thing) {
    console.log(thing);
  }

}

我知道简单的解决方案是将*ngIf移动到一个级别,但对于像在ul中循环列表项这样的场景,如果集合为空,我最终会得到一个空li,或者我的lis被多余的容器元素包装。

比如在这个地方。

注意控制台错误:

EXCEPTION: TypeError: Cannot read property 'name' of null in [{{thing.name}} in ShellComponent@5:12]

是我做错了什么还是这是个bug?


当前回答

你不能在同一个元素上使用多个结构指令。在ng-template中包装你的元素,并在那里使用一个结构指令

其他回答

你不能在同一个元素上使用ngFor和ngIf。你所能做的就是推迟填充你在ngFor中使用的数组,直到你的例子中的切换被单击。

这里有一个基本的(不是很好的)方法:http://plnkr.co/edit/Pylx5HSWIZ7ahoC7wT6P

你可以用另一种方法检查数组长度

<div *ngIf="stuff.length>0">
  <div *ngFor="let thing of stuff">
    {{log(thing)}}
    <span>{{thing.name}}</span>
  </div>
</div>

下表仅列出具有“初学者”值集的项目。 需要*ngFor和*ngIf来防止html中不需要的行。

最初有*ngIf和*ngFor在同一个<tr>标签上,但不工作。 为*ngFor循环添加了一个<div>,并将*ngIf放在<tr>标签中,如预期的那样工作。

<table class="table lessons-list card card-strong ">
  <tbody>
  <div *ngFor="let lesson of lessons" >
   <tr *ngIf="lesson.isBeginner">
    <!-- next line doesn't work -->
    <!-- <tr *ngFor="let lesson of lessons" *ngIf="lesson.isBeginner"> -->
    <td class="lesson-title">{{lesson.description}}</td>
    <td class="duration">
      <i class="fa fa-clock-o"></i>
      <span>{{lesson.duration}}</span>
    </td>
   </tr>
  </div>
  </tbody>

</table>

正如@Zyzle提到的,以及@Günter在评论(https://github.com/angular/angular/issues/7315)中提到的,这是不支持的。

<ul *ngIf="show">
  <li *ngFor="let thing of stuff">
    {{log(thing)}}
    <span>{{thing.name}}</span>
  </li>
</ul>

当列表为空时,没有空的<li>元素。甚至<ul>元素也不存在(正如预期的那样)。

填充列表时,没有多余的容器元素。

@Zyzle在他的评论中提到的github讨论(4792)也提出了另一个解决方案,使用<模板>(下面我使用您的原始标记‐使用<div>s):

<template [ngIf]="show">
  <div *ngFor="let thing of stuff">
    {{log(thing)}}
    <span>{{thing.name}}</span>
  </div>
</template>

这个解决方案也没有引入任何额外/冗余的容器元素。

在html中:

<div [ngClass]="{'disabled-field': !show}" *ngFor="let thing of stuff">
    {{thing.name}}
</div>

在css中:

.disabled-field {
    pointer-events: none;
    display: none;
}