ngOnChanges Example | Angular
child.component.ts
import { Component, OnInit, Input, SimpleChanges } from '@angular/core';
@Component({
selector: 'app-child',
template: `
<a (click)="changeFromChild()">Change from child</a>
<br/>
{{parentData}}
`
})
export class ChildComponent implements OnInit {
@Input() parentData: any;
constructor() {
}
ngOnInit() {
}
changeFromChild(){
this.parentData -= 1;
}
ngOnChanges(changes: SimpleChanges) {
console.log(changes)
}
}
parent.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-parent',
template: `
<a (click)="changeFromParent()">Change from parent</a>
<br/>
<app-child [parentData]=data></app-child>
`
})
export class ParentComponent implements OnInit {
data = 0
constructor() {
}
ngOnInit() {
}
changeFromParent(){
this.data += 1;
}
}
ngOnChanges() will fire before ngOnInit() and every time parentDatais updated from its parent component.
ngOnChanges() takes a changes argument of type SimpleChanges.
changeFromChild() won't call ngOnChanges()
changeFromParent() will call ngOnChanges()
When ngOnChanges() is called, this example simply logs the SimpleChanges instance.
The SimpleChanges instance looks like this...
class SimpleChange {
constructor(previousValue: any, currentValue: any, firstChange: boolean)
previousValue: any
currentValue: any
firstChange: boolean
isFirstChange(): boolean
}
Every time ngOnChanges() is called, the SimpleChanges instance captures the parentData's:
- previousValue
- currentValue
- firstChange (true the first time ngOnChanges is called)
Here is the SimpleChange object our example logs:
ngOnChanges(changes: SimpleChanges) {
console.log(changes)
}
//console output
{
parentData: { currentValue: 1, firstChange: false, previousValue: 0 }
}
What about multiple inputs?
Each bound variable is returned with its corresponding SimpleChanges instance in a single object.
//SimpleChanges object with multiple inputs
{
parentData: { currentValue: 1, firstChange: false, previousValue: 0 },
firstName: { currentValue: "Sam", firstChange: false, previousValue: "Eric" },
age: { currentValue: 25, firstChange: false, previousValue: 20 }
}
ngOnChanges vs ngOnInit
ngOnInit gets called only once when the component is initialized.
ngOnChanges gets called before ngOnInit and whenever a component's bound input is changed FROM THE PARENT COMPONENT.
Remember that ngOnChanges is specific to bound inputs on the component. This means if you don't have any @Input properties on a child, ngOnChanges will never get called.
ngOnInit is specific to the component being initialized. ngOnChanges is specific to @Input properties on a child component.
When should you use ngOnChanges?
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. ngOnChanges simply adds the benefit of tracking those changes with previous and current value.
Your thoughts?
remember that these lifecycle hooks are what make Angular 2+ be able to compete with React...
Specifically these life cycle hooks allow data to flow in a single direction (top down). This was a huge issue with the original Angular and something React got right with flux architecture.
When data changes are propagated from top down, you get more consistent results. Things fall into a hierarchy of updates and can't update each other like "two way data binding" and the original Angular.
So sorry for the tangent, but important to know that these kinds of lifecycle hooks are what make Angular apart of todays client side development conversation.
think of ngOnChanges() as a callback function when your state updates.
thanks for the great explanation on ngOnChanges. really appreciate the ngOnChanges example...why can't the official documentation explain this as clearly???
Another question I have is how these lifecycle hooks (in general) compare to React and other frameworks. From what I've heard, ReactJs is still king in terms of their diffing algo and performance.
SimpleChanges is key because it allows you to see thing that triggered change and current value...
You should ALWAYS use SimpleChanges with these lifecycle hooks...
ngOnChanges() == useEffect() in React???
if you use ngOnChanges without SimpleChanges..consider yourself screwed :)
this post does a really good job of explaining how ngOnChanges() works with parent components.
You have to remember that the parent inputs will always invoke ngOnChanges() from the child...
it is absolutely imperative that you use SimpleChanges with ngOnChanges.
this finally makes sense...thank you