我在尝试在同一元素上使用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
如果集合为空,或者我的li
包裹在冗余容器元素中。
此plnkr的示例。
请注意控制台错误:
EXCEPTION: TypeError: Cannot read property 'name' of null in [{{thing.name}} in ShellComponent@5:12]
我做错了什么还是这个错误?
答案 0 :(得分:537)
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>
答案 1 :(得分:45)
正如大家所指出的那样,即使在单个元素中有多个模板指令也在角度1.x中工作,但Angular 2中不允许这样做。 您可以在此处找到更多信息:https://github.com/angular/angular/issues/7315
解决方案是使用<template>
作为占位符,因此代码就像这样
<template *ngFor="let nav_link of defaultLinks" >
<li *ngIf="nav_link.visible">
.....
</li>
</template>
但出于某种原因,上述某些原因在2.0.0-rc.4
中不起作用,您可以使用此
<template ngFor let-nav_link [ngForOf]="defaultLinks" >
<li *ngIf="nav_link.visible">
.....
</li>
</template>
有了更新,现在2018年,角度v6建议使用<ng-container>
代替<template>
所以这是更新的答案。
<ng-container *ngFor="let nav_link of defaultLinks" >
<li *ngIf="nav_link.visible">
.....
</li>
</ng-container>
答案 2 :(得分:32)
我还有一个解决方案。
使用[hidden]
代替*ngIf
<div [hidden]="!show" *ngFor="let thing of stuff">
不同之处在于,*ngIf
会从DOM中删除元素,而[hidden]
实际上会使用CSS
样式播放,方法是设置display:none
答案 3 :(得分:29)
正如@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 discussion (4792)也提出了使用<template>
的另一种解决方案(下面我使用的是原始标记 - 使用<div>
s):
<template [ngIf]="show">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</template>
此解决方案也不会引入任何额外/冗余容器元素。
答案 4 :(得分:5)
您不能在同一元素上拥有ngFor
和ngIf
。您可以做的是暂停填充您在ngFor
中使用的阵列,直到您点击示例中的切换为止。
这是一种基本(不太好)的方法:http://plnkr.co/edit/Pylx5HSWIZ7ahoC7wT6P
答案 5 :(得分:3)
这会有效,但元素仍然在DOM中。
.hidden{
display: none;
}
<div [class.hidden]="!show" *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
答案 6 :(得分:3)
下表仅列出了具有&#34;初学者&#34;价值集。
需要*ngFor
和*ngIf
以防止html中出现不需要的行。
最初在*ngIf
标记上有*ngFor
和<tr>
,但不起作用。
为<div>
循环添加了*ngFor
,并将*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>
答案 7 :(得分:2)
现在从angular2 beta 8开始,我们可以在同一个组件see here上使用*ngIf
和*ngFor
。
替代:
有时我们无法在tr
,th
(table
)或li
(ul
)中使用HTML标记。我们无法使用其他HTML标记,但我们必须在相同的情况下执行某些操作,因此我们可以通过这种方式使用HTML5功能标记<template>
。
<template ngFor #abc [ngForOf]="someArray">
code here....
</template>
<template [ngIf]="show">
code here....
</template>
有关angular2 see here中结构指令的更多信息。
答案 8 :(得分:2)
你不能在同一元素的Angular中使用多个Structural Directive
,它会产生一个错误的混淆和结构,所以你需要在两个独立的嵌套元素中应用它们(或者你可以使用{{1} }),阅读Angular团队的这篇声明:
每个主机元素一个结构指令
有一天你会想要重复一段HTML,但只有当一个 特殊情况是真的。你会试着把 * ngFor 和 同一主机元素上的 * ngIf 。 Angular不会让你。你可以 仅对元素应用一个结构指令。
原因是简单。结构指令可以做复杂的事情 与宿主元素及其后代。当两个指令存在时 声称拥有相同的主机元素,哪一个优先?哪一个 应该先行,NgIf还是NgFor? NgIf能否取消效果 NgFor?如果是这样(似乎应该如此),应该怎么做 Angular概括了取消其他结构的能力 指令?
这些问题没有简单的答案。禁止多重 结构指令使他们没有实际意义。有一个简单的解决方案 这个用例:将 * ngIf 放在包装的容器元素上 * ngFor 元素。一个或两个元素可以是 ng-container ,因此您不必引入额外的HTML级别。
所以你可以使用ng-container
(Angular4)作为包装器(将从dom中删除)或div或span,如果你有类或其他属性如下所示:
ng-container
答案 9 :(得分:1)
<div *ngFor="let thing of show ? stuff : []">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
答案 10 :(得分:1)
在html中:
<div [ngClass]="{'disabled-field': !show}" *ngFor="let thing of stuff">
{{thing.name}}
</div>
在CSS中:
.disabled-field {
pointer-events: none;
display: none;
}
答案 11 :(得分:0)
您不能在同一元素上使用多个结构指令。在ng-template
中包装元素,并在其中使用一个结构指令
答案 12 :(得分:0)
您还可以使用 ng-template
(而不是模板。有关使用模板标记的注意事项,请参见注释)同时应用 * ngFor 和 ngIf 。这是一个示例,您可以在角度表中为同一 tr 元素同时使用 * ngIf和* ngFor 。
<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
标签而不是 ng-template
标签的警告是,它在某些地方抛出了StaticInjectionError
。
答案 13 :(得分:0)
self.renderer = [SCNRenderer rendererWithContext:_openGLContext options:nil];
self.renderer.autoenablesDefaultLighting = YES;
self.renderer.playing = YES;
self.renderer.scene = myAnimatedScene;
答案 14 :(得分:0)
app.component.ts
import {NgModule, Component} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
@Component({
selector: 'ngif-example',
template: `
<h4>NgIf</h4>
<ul *ngFor="let person of people">
<li *ngIf="person.age < 30"> (1)
{{ person.name }} ({{ person.age }})
</li>
</ul>
`
})
class NgIfExampleComponent {
people: any[] = [
{
"name": "yogesh ",
"age": 35
},
{
"name": "gamesh",
"age": 32
},
{
"name": " Meyers",
"age": 21
},
{
"name": " Ellis",
"age": 34
},
{
"name": " Tyson",
"age": 32
}
];
}
app.component.html
<ul *ngFor="let person of people" *ngIf="person.age < 30">
<li>{{ person.name }}</li>
</ul>
输出
Meyers(21)
答案 15 :(得分:0)
您可以通过检查数组长度来另一种方式
<div *ngIf="stuff.length>0">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</div>
答案 16 :(得分:0)
在另一种解决方案上,可能是在您不想显示它的情况下在您的for循环中放置一个空数组
<div *ngFor="let thing of show ? stuff : []">
其中“东西”是“事物”的数组,而“显示”要显示内容的布尔值
答案 17 :(得分:0)
我不想使用*ngFor
将div
包裹到另一个*ngIf
或使用[ngClass]
,所以我创建了一个名为show
的管道: / p>
show.pipe.ts
export class ShowPipe implements PipeTransform {
transform(values: any[], show: boolean): any[] {
if (!show) {
return[];
}
return values;
}
}
any.page.html
<table>
<tr *ngFor="let arr of anyArray | show : ngIfCondition">
<td>{{arr.label}}</td>
</tr>
</table>