I created my custom structural directive which should render the host element for each element in the passed array of items:
@Directive({
selector: '[appItems]'
})
export class ItemsDirective implements OnInit, OnChanges {
@Input('appItemsOf')
items: any[];
constructor(private container: ViewContainerRef,
private template: TemplateRef<any>) {
}
ngOnInit(): void {
this.container.createEmbeddedView(this.template);
}
ngOnChanges(): void {
this.container.clear();
for (const item of this.items) {
if (item) {
this.container.createEmbeddedView(this.template, {
$implicit: item,
index: this.items.indexOf(item)
});
}
}
}
}
Usage:
<div *appItems="let item of items">
Item: {{ item.name }}
</div>
Which, unfortunately, prints:
Item: 1
Item: 2
Item: 3
Item:
The last element is being created and rendered although the item array looks like:
items = [
{
name: '1'
},
{
name: '2'
},
{
name: '3'
}
]
I created a https://stackblitz.com/edit/angular-qwatckstackblitz showing this issue.
Why is this so and how should it be done properly?
Currently, the following is done:
NgOnChanges
is invokedNgOnInit
is invokedSo basically, once you create the the N-views for your collection, you create a further one during NgOninit
, resulting in N+1 embedded views in your template being generated.
Simply remove the content of NgOnInit
.