Skip to content
Advertisement

Why is ngOnChange not detecting @Input element change whil ngOnDetect was able to do so

Consider this plunker

Note: To observe the effect you have to rerun the app after the entering the link

import {Component, OnInit, Input, OnChanges, DoCheck} from 'angular2/core'

@Component({
  selector: 'sub',
  template: `
    <li  *ngFor="#elem of sub_list">
      <div>{{elem['name']}}</div>
    </li>
    `
})
export class Sub {

  @Input()
  sub_list: Object[];

  ngOnInit(){
    console.log('init');
    console.log(this.sub_list);
  } 

  ngOnChanges(){
    console.log('change');
    console.log(this.sub_list);
  }

  ngDoCheck() {
    console.log('check');
    console.log(this.sub_list);
  }

}
@Component({
  selector: 'my-app',
  template: `
    <div>
      <sub
        [sub_list]="my_list"
      >
      </sub>

    </div>

    `,
  directives: [Sub]
})
export class App {

  my_list: Object[] = [];

  ngOnInit() {
      var vm = this;

    setTimeout(function() {
          for(var i = 0; i < 100; i++) {

        vm.my_list.push({
          'index' : i,
          'name'  : i
        });
      }
    }, 100);

  }
}

If I try to print out this.sub_list in Sub‘s ngOnChange the browser outputs an empty list.

However we can see that ngDoCheck still correctly captures the change.

Is there a specific reason for this?

Advertisement

Answer

In your case ngOnChanges won’t be called for updates on the array. As a matter of fact, Angular2 detects updates based on references. I mean if the reference of the whole array doesn’t change (it’s the case when adding an element in it using the push method), the ngOnChanges method won’t be called.

In your case your array is null when ngOnChanges is called because it’s called before the input element is set.

There are two ways to detect changes in this case:

  • update the whole array reference using methods like slice (after the push) or concat.

    this.myArray.push({...});
    this.myArray.push = this.myArray.push.slice();
    
  • leverage the ngDoCheck method with the IterableDiffers class to manually check updates. The class allows you to register callbacks to be notified when an element is added (or remove) in an array.

See these links for more details:

Advertisement