Reputation: 671
My Angular 11 (Ioinc 5) application has 2 components: A ContainerComponent
and a BoxComponent
.
Both components are completely translucent (template: '<ng-content></ng-content>'
)
The container component needs to keeps track of the number of box components that a third component places into it.
My solution fails when the third component uses *ngFor to place the boxes into the container (Option B below)
container.component.ts
import { Component, ContentChildren, QueryList, AfterContentInit } from '@angular/core';
import { BoxComponent } from './box.component';
@Component({
selector: 'container',
template: '<ng-content></ng-content>',
styleUrls: ['container.component.scss'],
})
export class ContainerComponent implements AfterContentInit {
// track the number of boxes
private count: number = 0;
@ContentChildren(BoxComponent)
private boxes!: QueryList<BoxComponent>;
ngAfterContentInit(): void {
this.count++;
console.log(count); // Result see below
}
}
A third component places n
BoxComponent
s into a ContainerComponent
.
Option A: n boxes hardcoded into template of third component
<container>
<box>Box 1</box>
<box>Box 2</box>
// ...
<box>Box n</box>
</container>
Option B: n boxes added into the template of the third component using *ngFor directive
<container *ngFor="let box of boxes">
<box>{{box.label}}</box>
</container>
Difference between option A and option B
When using option A, Angular calls ngAfterContentInit
only once and the result is
count = n
When using option B, Angular calls ngAfterContentInit
n times and the count
is always 1.
count = 1, 1, ..., 1 // n times
I find this behavior very strange because that means that Angular creates a new instance of ContainerComponent
for each BoxComponent
.
Upvotes: 2
Views: 215
Reputation: 654
I believe this is the right behaviour. The ngFor directive will iterate through the boxes list, creating one instance of the injected component for each element.
Maybe the behaviour you expect will be achieved if you put ngFor in the box component:
<container>
<box *ngFor="let box of boxes">{{box.label}}</box>
</container>
Cheers!
Upvotes: 3