46
votes

In my angular application, i came up with a situation where ngOnchanges should only be called when the inputs are bound to changes. so, is there a way to stop the execution of ngOnChanges before ngOnInit. Is there a way to accomplish this. Thanks in Advance.

3
This is normal behavior. Take a look to Lifecycle Hooks in Angular 2 docs. Instead of ngOnChange, you can try ngAfterViewInit() for example (Respond after Angular initializes the component's views and child views) - mickdev
Yes, I know that. Is there any way to listen to the change in my inputs after ngoninit has executed? - RemyaJ
Right after ngOnInit(), ngDoCheck() is executed (but it will be executed multiple times). If you are using reactive forms, you can keep ngOnChange and check if the form fields are set (if(this.form.get('yourField').value) ...). Something similar to what you have now. - mickdev
Yes I did try with ngdocheck but it went into a kind of infinite loop. This is not a form, and dataready is something I got as input from another component and I want to listen to its change. - RemyaJ
No. But if you provide information about the actual problem you're trying to solve, we can probably offer other approaches that can help solving your problem. - Günter Zöchbauer

3 Answers

80
votes

You cannot prevent this behavior, but you can:

Use a Subject :

class Foo implements OnChanges,OnInit,OnDestroy{

  onChanges = new Subject<SimpleChanges>();

  ngOnInit(){
    this.onChanges.subscribe((data:SimpleChanges)=>{
      // only when inited
    });
  }
  ngOnDestroy(){
    this.onChanges.complete();
  }

  ngOnChanges(changes:SimpleChanges){
    this.onChanges.next(changes);
  }

}

Use a boolean property:

class Foo implements OnChanges,OnInit{

  initialized=false;

  ngOnInit(){
    // do stuff
    this.initialized = true;
  }

  ngOnChanges(changes:SimpleChanges){
    if(this.initialized){
      // do stuff when ngOnInit has been called
    }
  }

}

Use the SimpleChanges API

You can also check the SimpleChange.isFirstChange() method :

isFirstChange() : boolean Check whether the new value is the first value assigned.

class Foo implements OnChanges,OnInit{

  @Input()
  bar:any;

  ngOnInit(){
    // do stuff
  }

  ngOnChanges(changes:SimpleChanges){
    if(!changes["bar"].isFirstChange()){
      // do stuff if this is not the initialization of "bar"
    }
  }

}
2
votes

One method I have found that works is based on the fact that the input values all have a previous value property. If the input has not previously been set then that value will be CD_INIT_VALUE (as a string). So you can make a condition that your block of code in ngOnChanges should only run if the previous value is not CD_INIT_VALUE. Here's an example for your case where you're testing ALL the input values:

ngOnChanges(changes: SimpleChanges) {
  let initialized: boolean = true;
  for (let prop in changes) {
    if (changes[prop].previousValue.toString() === 'CD_INIT_VALUE') {
      initialized = false;
      //we can break here since if any item is not initialized
      //we will say the inputs are NOT initialized
      break;
    }
  }

  if (initialized) {
    //code you want to execute
  }    
}

There are probably more elegant solutions but I've found this works. This is probably too late to help you but may help others as when I googled this I found this question. The solution was something I figured out from debugging.

0
votes

In case it helps anyone here's an example of how I implemented the isFirstChange() solution suggested by @n00dl3 into my AngularJS app:

this.$onChanges = (changes) => {
    if (!changes.value.isFirstChange()) {
        // do stuff
    }
};