Abhishek Soni
Abhishek Soni

Reputation: 593

ngOnChanges is calling up multiple times

I have generated multiple ion-slides using ngFor, and inserted a component there. It is calling ngOnChanges multiple time. I want it should call only once, so that I can call my api.

I have tried using multiple angular lifecycle hooks.

This is how I created my slides, menu has 19 elements

<ion-slides #slides [options]="slideOpts" (ionSlideDidChange)="slideChanged($event)">
<ion-slide *ngFor="let i of menu; let j = index">
  <h1>{{ i.name }}</h1>
  <app-homenews [categoryId]="currentCategoryId" ></app-homenews>
</ion-slide>
</ion-slides>

This is how we are making change detection

@Input() categoryId: number;

ngOnChanges(changes: SimpleChanges) {
   let chg = changes['categoryId'];
   console.log(chg.currentValue);
} 

I want it to be called only once, it is calling 19 times now.

Can I use rxjs here ?

Upvotes: 4

Views: 14017

Answers (4)

Steve Chacko
Steve Chacko

Reputation: 135

While the other answers are technically correct, I feel it is better to use a getter-setter or the SimpleChanges object that you already passed to the lifecycle hook, rather than a isFirstRun flag. The SimpleChanges object contains all the information you already need.

class SimpleChange {
  constructor(previousValue: any, currentValue: any, firstChange: boolean)
  previousValue: any
  currentValue: any
  firstChange: boolean
  isFirstChange(): boolean
}

During runtime, an object containing one/many SimpleChanges objects corresponding to the component's Input variables will be passed into NgOnChanges, having the format above. it would be easier to check the firstChange value like I have done below;

@Input() categoryId: number;

ngOnChanges(changes: SimpleChanges) {
   if(changes['categoryId'].firstChange) {
     let chg = changes['categoryId'];
     console.log(chg.currentValue);
     //other program logic
   }
} 

Please note: if you're inputting data from an API response into a child component, chances are before the API call is run a null value will be sent on initialisation, and firstChange will be set to true for that Input. In that particular case, checking the previous value as null and whether the current value is present should be enough.

Upvotes: 0

sreejithsdev
sreejithsdev

Reputation: 1210

ngOnChanges runs when there is change in value of Input variable comes from a template binding.So triggering it multiple times is a normal behavior.If you want to execute some code only once you can use it like this

@Input() isFirstRun;
ngOnChanges(changes: SimpleChanges) {
  if(this.isFirstRun){
     let chg = changes['categoryId'];
     console.log(chg.currentValue);
  }
}

<ion-slide *ngFor="let i of menu; let j = index">
  <h1>{{ i.name }}</h1>
  <app-homenews [isFirstRun]="j===0?true:false" [categoryId]="currentCategoryId" ></app-homenews>
</ion-slide>

Upvotes: 5

Nico
Nico

Reputation: 518

I used this method one times to avoid the use of ngOnChanges cycle.

In your component :

private _changes;
private id;
@Input()
  set changes(changes) {     

      this._changes= changes;
      this.id = changes[id];

    }
  }
  get changes(): string {
    return this._changes;
  }

Upvotes: 0

Barkha
Barkha

Reputation: 722

You can add a isFirstRun flag in a service and use that in your component You can continue using ngOnchanges as it will be helpful in case the value changes

ngOnChanges(changes: SimpleChanges) {
if (this.flagService.isFirstRun || value has changed) {
// call API
}
} 

Upvotes: 0

Related Questions