Can you programatically trigger angular's change detection when mutating a component property in angular2?
@Component({
selector: 'my-component',
})
class MyComponent implements OnChanges {
@Input() message: string;
ngOnChanges(changeRecord) {
for (var change in changeRecord) {
console.log('changed: ' + change);
}
}
doSomething() {
// I want ngOnChanges to be called some time after I set the
// message. Currently it is only called if the host element
// changes the value of [message] on the element.
this.message = 'some important stuff';
}
}
That's because ngOnChanges is called by Angular as the component is instantiated. It is also invoked before ngOnInit in case you were unaware.
Use ngOnChanges whenever you want to detect changes from a variable decorated by @Input. Remember that only changes from the parent component will trigger this function. Also remember that changes from the parent still update the child value even without implementing ngOnChanges.
During change detection, when Angular checks components' input properties for change, it uses (essentially) === for dirty checking. For arrays, this means the array references (only) are dirty checked. Since the rawLapsData array reference isn't changing, ngOnChanges() will not be called.
ngOnChanges only runs when the Input change comes from a template binding like <component [someInput]="aValue"> . If you set it manually like this component. someInput = aValue , that happens outside the change detection cycle and you need to let Angular know somehow that you've changed something.
The reason it doesn’t work can be found in the source code.
https://github.com/angular/angular/blob/885f1af509eb7d9ee049349a2fe5565282fbfefb/packages/core/src/view/provider.ts
Where ngOnChanges is called from, and where the SimpleChanges structure is built are very much tied into the component / directive code.
It’s not just a ‘change tracker’ running that looks over every property however it was set, so ngOnChanges only works for bindings set by parent components.
This is where ngDoCheck comes in and possibly KeyValueDiffers.
See also:
https://netbasal.com/angular-the-ngstyle-directive-under-the-hood-2ed720fb9b61 https://juristr.com/blog/2016/04/angular2-change-detection/
I was having the same issue, and this is a simple but not very elegant workaround I am using. Pass in another property to force trigger ngOnChanges method
<div poll-stat-chart [barData]="barData" [changeTrigger]="changeTrigger"></div>
In the parent component class, whenever you want to manually fire the ngOnChanges method on child component, just modify "changeTrigger" property
ParentComponent Class (poll-stat-chart is the child component)
@Component({
directives: [PollStatChartCmp],
template: `
<div poll-stat-chart [barData]="barData" [changeTrigger]="changeTrigger">
</div>
<button (click)="triggerChild()"></button>
`
}
export class ParentComponent {
changeTrigger = 1;
barData = [{key:1, value:'1'}, {key:2, value'2'}];
triggerChild() {
this.barData[0].value = 'changedValue';
//This will force fire ngOnChanges method of PollStatChartComponent
this.changeTrigger ++ ;
}
}
And then in child component class, add a property [changeTrigger]
@Component({
selector: '[poll-stat-chart]',
inputs: ['barData', 'changeTrigger'],
template: `
<h4>This should be a BAR CHAR</h4>
`
})
export class PollStatChartCmp {
barData;
changeTrigger;
constructor(private elementRef: ElementRef) {
this.render();
}
ngOnChanges(changes) {
console.log('ngOnChanges fired');
this.render();
}
render() { console.log('render fired');}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With