Why ngOnChanges is not running in this case? (Angular Docs Example)

Issue

I’m learning angular and I run into this ngOnChanges example from Angular docs (stackblitz) :

on-changes-parent.component.html

<h2>{{title}}</h2>
<label for="power-input">Power: </label>
<input type="text" id="power-input" [(ngModel)]="power">
<label for="hero-name"> Hero.name: </label>
<input type="text" id="hero-name" [(ngModel)]="hero.name">

<button type="button" (click)="reset()">Reset Log</button>

<on-changes [hero]="hero" [power]="power"></on-changes>

on-changes-parent.component.html

export class OnChangesParentComponent {
  hero!: Hero;
  power = '';
  title = 'OnChanges';
  @ViewChild(OnChangesComponent) childView!: OnChangesComponent;

  constructor() {
   this.reset();
  }

  reset() {
    // new Hero object every time; triggers onChanges
    this.hero = new Hero('Windstorm');
    // setting power only triggers onChanges if this value is different
    this.power = 'sing';
    if (this.childView) {
      this.childView.reset();
    }
  }
}

on-changes.component.ts

@Component({
  selector: 'on-changes',
  template: `
  <div class="info">
    <p>{{hero.name}} can {{power}}</p>

    <h3>Change Log</h3>
    <div *ngFor="let chg of changeLog" class="log">{{chg}}</div>
  </div>
  `
})
export class OnChangesComponent implements OnChanges {
  @Input() hero!: Hero;
  @Input() power = '';

  changeLog: string[] = [];

  ngOnChanges(changes: SimpleChanges) {
    for (const propName in changes) {
      console.log(propName)
      const chng = changes[propName];
      const cur  = JSON.stringify(chng.currentValue);
      const prev = JSON.stringify(chng.previousValue);
      this.changeLog.push(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
    }
  }

  reset() { this.changeLog = []; }
}

After adding console.log to ngOnChanges I noticed that it’s running when I update Power input , however, it’s not running when I update Hero.name. I expected ngOnChanges to run in both cases. What did I miss? I’d appreciate your explanation.

Solution

It doesn’t trigger because it is still the same hero you’re referencing, only with a different name. Since Angular uses === to check changes it decides the object didn’t change.

A way to fix this is creating a new hero object each time the name changes or implement the ngDoCheck interface to implement your custom change detection.

Answered By – Felix

Answer Checked By – Marie Seifert (AngularFixing Admin)

Leave a Reply

Your email address will not be published.