Reputation: 1892
I have the following template
<div *ngIf="hotels$ | async as hotels; else loadGif ">
<div *ngFor="let hotel of hotels | hotelsFilter: _filteredType; first as f; index as i "
appInit [hotel]="hotel " [first]="f ">
<app-card appHighlight [hotel]=hotel></app-card>
</div>
</div>
And appInit directive is written to idenify the fist element of hotels list after the list is filtered. This is ngInit method of appInit directive:
constructor(
private __hotelsService: HotelsService
) { }
@Input()
public hotel: Hotel;
@Input()
public first: boolean;
public ngOnInit(): void {
if (this.first) {
this.__hotelsService.selectedHotel$.next(this.hotel);
console.log('first init ' + this.hotel.name);
}else{
console.log('not first init ' + this.hotel.name);
}
}
The problem is that ngOnInit
method of the directive is called not each time when the list of hotels is filtered and re-rendered. The question is why and when ngOnInit is really should be called?
Upvotes: 0
Views: 5483
Reputation: 1754
ngOnInit will only be called once when the component is initialized. As per your need, you should use ngOnChanges which will be called when input properties get changed.
For more info on lifecycle hooks: https://angular.io/guide/lifecycle-hooks
Upvotes: 3
Reputation: 657676
Every time change detection runs and updates inputs that have a value bound to them ngOnChanges
is called.
ngOnInit
is called the first time after ngOnChanges
is called.
For more details see https://angular.io/guide/lifecycle-hooks
When *ngFor
renders the elements, it recognizes when values are the same and reuses rendered items.
This is why ngOnInit
is not called after the filter changes for items that were also rendered before the filter changed.
You can instead use ngOnChanges
which will be called every time an input is updated, or you can make the inputs getters
_first: boolean,
@Input()
public set first(value: boolean) {
this._first = value;
if (this.first) {
this.__hotelsService.selectedHotel$.next(this.hotel);
console.log('first init ' + this.hotel.name);
}else{
console.log('not first init ' + this.hotel.name);
}
}
public get first() : boolean {
return this._first;
}
Upvotes: 3