* ngIf和* ngFor在同一元素上导致错误

问题描述 投票:343回答:14

我试图在同一元素上使用Angular qazxsw poi和qazxsw poi时遇到问题。

当试图遍历*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,或者我的uls包含在冗余的容器元素中。

这个li的例子。

请注意控制台错误:

li

我做错了什么或这是一个错误?

angular ngfor angular-ng-if
14个回答
566
投票

Angular v2不支持同一元素上的多个结构指令。 作为一种解决方法,使用plnkr元素,它允许您为每个结构指令使用单独的元素,但它不会标记到DOM。

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

<ng-container>(Angular v4之前的<ng-container *ngIf="show"> <div *ngFor="let thing of stuff"> {{log(thing)}} <span>{{thing.name}}</span> </div> </ng-container> )允许执行相同的操作,但语法不同,令人困惑,不再推荐

<ng-template>

2
投票

Updated to angular2 beta 8

现在从angular2 beta 8我们可以在相同的组件<div [ngClass]="{'disabled-field': !show}" *ngFor="let thing of stuff"> {{thing.name}} </div> 上使用.disabled-field { pointer-events: none; display: none; } *ngIf

备用:

有时我们不能在*ngForsee heretr)或thtable)中使用HTML标签。我们不能使用另一个HTML标签,但我们必须在相同的情况下执行某些操作,因此我们可以通过这种方式使用HTML5功能标记li

ngFor using template:

ul

ngIf using template:

<template>

有关angular2 <template ngFor #abc [ngForOf]="someArray"> code here.... </template> 中结构指令的更多信息。


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

1
投票

您还可以使用see here(而不是模板。请参阅使用模板标记的注释说明),以便在同一HTML元素上同时应用* ngFor和ngIf。下面是一个示例,您可以将* ngIf和* ngFor用于角度表中的相同tr元素。

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

哪里有ng-template

注意:

使用<tr *ngFor = "let fruit of fruiArray"> <ng-template [ngIf] = "fruit=='apple'> <td> I love apples!</td> </ng-template> </tr> 标签而不是fruiArray = ['apple', 'banana', 'mango', 'pineapple']标签的警告是它在某些地方抛出template


0
投票

ng-template

0
投票

您不能在同一元素上使用多个结构指令。将您的元素包裹在StaticInjectionError中并在那里使用一个结构指令


50
投票

正如大家所指出的那样,尽管在单个元素中有多个模板指令在角度1.x中工作,但在Angular 2中不允许这样做。您可以从这里找到更多信息:<template>

2016 angular 2 beta

解决方案是使用<ng-template [ngIf]="show"> <div *ngFor="let thing of stuff"> {{log(thing)}} <span>{{thing.name}}</span> </div> </ng-template> 作为占位符,因此代码就是这样的

https://github.com/angular/angular/issues/7315

但由于某些原因,上述情况在<template>不起作用,在这种情况下你可以使用它

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

Updated Answer 2018

随着更新,现在2018年角v6推荐使用2.0.0-rc.4而不是<template ngFor let-nav_link [ngForOf]="defaultLinks" > <li *ngIf="nav_link.visible"> ..... </li> </template>

所以这是更新的答案。

<ng-container>

35
投票

我还有一个解决方案。

使用<template>而不是<ng-container *ngFor="let nav_link of defaultLinks" > <li *ngIf="nav_link.visible"> ..... </li> </ng-container>

[hidden]

区别在于*ngIf将从DOM中删除元素,而<div [hidden]="!show" *ngFor="let thing of stuff"> 实际上通过设置display:none来播放*ngIf样式


29
投票

正如@Zyzle所提到的,@Günter在评论中提到([hidden]),这是不受支持的。

CSS

当列表为空时,没有空的https://github.com/angular/angular/issues/7315元素。甚至<ul *ngIf="show"> <li *ngFor="let thing of stuff"> {{log(thing)}} <span>{{thing.name}}</span> </li> </ul> 元素也不存在(如预期的那样)。

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

@Zyzle在评论中提到的<li>也提出了使用<ul>的另一种解决方案(下面我使用你的原始标记和破折号;使用github discussion (4792)s):

<template>

此解决方案也不会引入任何额外/冗余容器元素。


5
投票

你不能在同一元素上有<div><template [ngIf]="show"> <div *ngFor="let thing of stuff"> {{log(thing)}} <span>{{thing.name}}</span> </div> </template> 。您可以做的是暂停填充您在ngFor中使用的数组,直到单击示例中的切换。

这是你可以做到的基本(不太好)的方式:ngIf


3
投票

这将工作,但元素仍将在DOM中。

ngFor

http://plnkr.co/edit/Pylx5HSWIZ7ahoC7wT6P

3
投票

下表仅列出设置了“初学者”值的项目。需要.hidden{ display: none; } <div [class.hidden]="!show" *ngFor="let thing of stuff"> {{log(thing)}} <span>{{thing.name}}</span> </div> 来防止html中不需要的行。

最初在相同的*ngFor标签上有*ngIf*ngIf,但不起作用。为*ngFor循环添加了<tr>并将<div>放在*ngFor标签中,按预期工作。

*ngIf

3
投票

你不能在同一个元素上使用Angular中的多个<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> ),从Angular团队阅读这个声明:

每个主机元素一个结构指令

有一天你会想要重复一段HTML,但只有在特定条件成立时才会这样。您将尝试将* ngFor和* ngIf放在同一主机元素上。 Angular不会让你。您可以只对元素应用一个结构指令。

原因很简单。结构指令可以与宿主元素及其后代做复杂的事情。当两个指令声称属于同一个主机元素时,哪一个优先?哪个应该先行,NgIf还是NgFor? NgIf可以取消NgFor的效果吗?如果是这样(似乎应该如此),Angular应如何概括取消其他结构指令的能力?

这些问题没有简单的答案。禁止多个结构指令使它们没有实际意义。这个用例有一个简单的解决方案:将* ngIf放在包装* ngFor元素的容器元素上。一个或两个元素可以是ng-container,因此您不必引入额外的HTML级别。

因此,如果你有类或其他一些属性,你可以使用Structural Directive(Angular4)作为包装器(将从dom中删除)或div或span:

ng-container

3
投票

在HTML中:

ng-container

在css中:

<div class="right" *ngIf="show">
  <div *ngFor="let thing of stuff">
    {{log(thing)}}
    <span>{{thing.name}}</span>
  </div>
</div>
© www.soinside.com 2019 - 2024. All rights reserved.