我在尝试在同一个元素上使用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?


当前回答

正如每个人都指出的那样,即使在一个元素中有多个模板指令在angular 1中也是有效的。x在Angular 2中是不允许的。 你可以在这里找到更多信息:https://github.com/angular/angular/issues/7315

2016年角2

解决方案是使用<template>作为占位符,因此代码如下所示

<template *ngFor="let nav_link of defaultLinks"  >
   <li *ngIf="nav_link.visible">
       .....
   </li>
</template>

但出于某种原因,上述在2.0.0-rc中不工作。在那种情况下你可以用这个

<template ngFor let-nav_link [ngForOf]="defaultLinks" >
   <li *ngIf="nav_link.visible">
       .....
   </li> 
</template>

2018年最新答案

随着更新,现在在2018年angular v6推荐使用<ng-container>而不是<template>

这是最新的答案。

<ng-container *ngFor="let nav_link of defaultLinks" >
   <li *ngIf="nav_link.visible">
       .....
   </li> 
</ng-container>

其他回答

正如每个人都指出的那样,即使在一个元素中有多个模板指令在angular 1中也是有效的。x在Angular 2中是不允许的。 你可以在这里找到更多信息:https://github.com/angular/angular/issues/7315

2016年角2

解决方案是使用<template>作为占位符,因此代码如下所示

<template *ngFor="let nav_link of defaultLinks"  >
   <li *ngIf="nav_link.visible">
       .....
   </li>
</template>

但出于某种原因,上述在2.0.0-rc中不工作。在那种情况下你可以用这个

<template ngFor let-nav_link [ngForOf]="defaultLinks" >
   <li *ngIf="nav_link.visible">
       .....
   </li> 
</template>

2018年最新答案

随着更新,现在在2018年angular v6推荐使用<ng-container>而不是<template>

这是最新的答案。

<ng-container *ngFor="let nav_link of defaultLinks" >
   <li *ngIf="nav_link.visible">
       .....
   </li> 
</ng-container>

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

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

<!——因为angular2稳定发布的多个指令不支持单个元素(来自文档),你仍然可以像下面这样使用它——> < ul类= "列表组" > <template ngFor let-item [ngForOf]="stuff" [ngForTrackBy]="trackBy_stuff"> <李* ngIf = " item.name " class = " list-group-item > {{item.name}} < /李> < /模板> < / ul >

更新到angular2 beta 8

现在从angular2 beta 8开始,我们可以在同一个组件上使用*ngIf和*ngFor。

可选:

有时我们不能在tr、th (table)或li (ul)中使用HTML标记。我们不能使用另一个HTML标签,但我们必须在相同的情况下执行一些操作,所以我们可以HTML5功能标签<template>以这种方式。

ngFor使用模板:

<template ngFor #abc [ngForOf]="someArray">
    code here....
</template>

ngIf使用模板:

<template [ngIf]="show">
    code here....
</template>    

有关angar2中结构指令的更多信息,请参见这里。

Angular v2不支持同一个元素上有多个结构指令。 作为一种变通方法,使用<ng-container>元素,它允许您为每个结构指令使用单独的元素,但它不会被标记到DOM中。

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

<ng-template> (Angular v4之前的<template>)允许做同样的事情,但使用了不同的语法,这很容易混淆,不再推荐使用

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