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 >
<p>{{hero.name}} can {{power}}</p>
<h3>Change Log</h3>
<div *ngFor="let chg of changeLog" >{{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.
CodePudding user response:
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.