我在尝试在同一个元素上使用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中,你不能在同一个元素上使用多个结构指令,这会造成严重的混乱和结构,所以你需要在两个独立的嵌套元素中应用它们(或者你可以使用ng-container),阅读Angular团队的这句话:
One structural directive per host element
Someday you'll want to repeat a block of HTML but only when a
particular condition is true. You'll try to put both an *ngFor and
an *ngIf on the same host element. Angular won't let you. You may
apply only one structural directive to an element.
The reason is simplicity. Structural directives can do complex things
with the host element and its descendents. When two directives lay
claim to the same host element, which one takes precedence? Which
should go first, the NgIf or the NgFor? Can the NgIf cancel the effect
of the NgFor? If so (and it seems like it should be so), how should
Angular generalize the ability to cancel for other structural
directives?
There are no easy answers to these questions. Prohibiting multiple
structural directives makes them moot. There's an easy solution for
this use case: put the *ngIf on a container element that wraps the
*ngFor element. One or both elements can be an ng-container so you don't have to introduce extra levels of HTML.
所以你可以使用ng-container (Angular4)作为包装器(将从dom中删除),如果你有class或其他一些属性,可以使用div或span:
<div class="right" *ngIf="show">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</div>
在Angular中,你不能在同一个元素上使用多个结构指令,这会造成严重的混乱和结构,所以你需要在两个独立的嵌套元素中应用它们(或者你可以使用ng-container),阅读Angular团队的这句话:
One structural directive per host element
Someday you'll want to repeat a block of HTML but only when a
particular condition is true. You'll try to put both an *ngFor and
an *ngIf on the same host element. Angular won't let you. You may
apply only one structural directive to an element.
The reason is simplicity. Structural directives can do complex things
with the host element and its descendents. When two directives lay
claim to the same host element, which one takes precedence? Which
should go first, the NgIf or the NgFor? Can the NgIf cancel the effect
of the NgFor? If so (and it seems like it should be so), how should
Angular generalize the ability to cancel for other structural
directives?
There are no easy answers to these questions. Prohibiting multiple
structural directives makes them moot. There's an easy solution for
this use case: put the *ngIf on a container element that wraps the
*ngFor element. One or both elements can be an ng-container so you don't have to introduce extra levels of HTML.
所以你可以使用ng-container (Angular4)作为包装器(将从dom中删除),如果你有class或其他一些属性,可以使用div或span:
<div class="right" *ngIf="show">
<div *ngFor="let thing of stuff">
{{log(thing)}}
<span>{{thing.name}}</span>
</div>
</div>