Ekaterina
Ekaterina

Reputation: 1892

When is ngOnInit method called?

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

Answers (2)

Ankit Kapoor
Ankit Kapoor

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

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

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

Related Questions