In this tutorial, we are going to learn how to use ngOnChanges lifecycle hook in angular, we will also see the limitation of using it and why we need to use other angular lifecycle hook functions in some cases unstated of using ngOnChanges, we will see all that through a basic example step by step.
Table of Contents
Angular Lifecycle Hooks
Angular has 8 lifecycle hooks, but in this tutorial, we will cover only the ngOnChanges lifecycle hook
ngOnChanges lifecycle hook Syntax and usage note
@Component({selector: 'my-cmp', template: `...`})
class MyComponent implements OnChanges {
@Input() prop: number = 0;
ngOnChanges(changes: SimpleChanges) {
// changes.prop contains the old and the new value...
}
}
Source : angular.io
What is ngOnChanges lifecycle hook in Angular ?
As we know, Angular lifecycle hooks are timed callback functions, that means, every lifecycle hook has an exact time and order of execution.
The execution of the hook is based on a fired event from the detection cycle. The first fired event will dispatch the callback of the ngOnchanges method, it’s fired before even the ngOnInit lifecycle hook.
As we know, angular providing us a very useful tool called data-binding that used to manage the data transfer between our components or between the user interface and the component.
I’m speaking about the data-binding, because the ngOnChanges lifecycle hook is based essentially on it,
ngOnChange lifecycle hook callback is immediately fired when angular detects any changes of the data-bound input property.
So if you pass data from the parent component to the child component using the property binding (@Input
decorator), angular will detect the changes and fires the callback.
So if there is no property data-binding used in your component, Angular will not fire the ngOnChanges
callback function.
The ngOnChanges lifecycle hook is very useful when we want to detect the changes that were being made from the parent, but there are some limitations.
In some cases, the ngOnChanges is not enough to detect all changes because it uses the property reference to check the difference, so it can’t detect the changes if you update the object property.
For example, if you pass an object User from the parent component then you update the age or the username property of the User object, in this case the Angular will not fire the event to dispatch the callback. Because it has the same reference of the User object.
To resolve this problem, you need to update the object reference
, not only the object property
.
Example : this.user = {…this.user, name: ‘XperTuto’};
You can also resolve this problem by using another angular lifecycle hook like ngDoCheck.
How to use ngOnChanges lifecycle hook in Angular ?
To explain better how ngOnChanges lifecycle hook in angular works,
We will create a simple Angular application that containing two components, a parent component and a child component, and we will try to pass the data from the parent to the child then we will update the inputs using a simple click button.
parent-component.ts :
import { Component} from '@angular/core';
@Component({
selector: 'app-root',
template: `
Update UserName
`,
})
export class ParentComponent{
user = {
name:"Aouidane",
webSite: 'XperTuto.com'
}
updateUser() : void{
// if we update only the property the ngOnChange doesn't work
// this.user.name = 'XperTuto';
this.user = {...this.user, name: 'amine'};
}
}
child-component.ts :
import { Component, OnInit, OnChanges} from '@angular/core';
@Component({
selector: 'app-child',
template: ` Here is the user name: {{ user.name }}`,
})
export class ChildComponent implements OnInit, OnChanges {
@Input() user: any;
ngOnInit() {
console.log('[ngOnInit] userName :'+ this.user?.name);
}
ngOnChanges(){
console.log('[ngOnChanges] username :'+ this.user?.name);
}
}
When we run our application, Angular fires the ngOnInit by default and while the component has an input data-bound, it will fire also the ngOnchanges lifecycle hook.
When we check the logs, we will see the following output :
[ngOnChanges] username : Aouidane
[ngOnInit] username : Aouidane
Now let’s update the username using the button click from the parent component.
We will have the following output :
[ngOnChanges] username : Amine
// no log for ngOnInit
You will notice that only the ngOnChanges lifecycle hook was fired,
that because the ngOnInit executes only one time after the first ngOnChanges
lifecycle hook.
So if there are any updates of the input data-bound, the ngOnInit will never be executed by Angular. (See this Tutorial for more details : how to use ngOnInit lifecycle hook ).
Angular ngOnChanges : SimpleChanges Example
ngOnChanges method uses a parameter of type SimpleChanges that providing us the new and the previous values of the component inputs after the changes.
let’s take our previous example and try to use the SimpleChanges argument.
import { Component,OnChanges,SimpleChanges} from '@angular/core';
@Component({
selector: 'app-child',
template: ` Here is the user name: {{ user.name }}`,
})
export class ChildComponent implements OnChanges {
@Input() user: any;
ngOnChanges(changes: SimpleChanges){
const change = changes['user'];
console.log('[ngOnChanges] Previous username value :'+ change.previousValue?.name);
console.log('[ngOnChanges] New username value :'+ change.currentValue?.name);
}
}
We are using our previous example , so we pass the userName from the parent ( by default ‘Aouidane’) and when we click the button we update the value to ‘Amine’ .
Now if we run our application and check the logs we will get he following outputs :
[ngOnChanges] Previous username value : undefined
[ngOnChanges] New username value : Aouidane
as you see we don’t have a previous value when we load the page.
now when we update the userName using the button click from the parent and we change the value of the userName to ‘Amine’ unstead of ‘Aouidane’ ( see the previous example) we will have the following logs :
[ngOnChanges] Previous username value : Aouidane
[ngOnChanges] New username value : Amine
References
ngOnChanges lifecycle hook Recapitulation
- ngOnChanges lifecycle hook is fired the first one by Angular ( before even the ngOnInit )
- ngOnChanges is fired by angular for every update of the input data-bound
- ngOnChanges can't detect the input changes if the object reference remains the same
- ngOnChanges provides an object of type SimpleChanges that contains the current and the previous values
Clone and Run the project
To download and run the example, please follow the steps :
1- Clone the source code from XperTuto git repository using the following command :
git clone https://github.com/www-xperTuto-com/ngOnChanges_Lifecycle_hook.git
2- Install the node dependencies using NPM command line : npm install
3- Run the application using the following command : ng serve
4- Access to the project through the URL : http://localhost:4200
Read More About Angular Lifecycle hooks:
- How to use ngAfterViewInit lifecycle hook ?
- How to use ngOnChanges lifecycle hook ?
- How to use ngOnInit lifecycle hook ?
- How to use ngDoCheck lifecycle hook in angular ?
- How to use ngAfterContentInit lifecycle hook ?
- How to use ngAfterContentChecked lifecycle hook ?
- How to use ngAfterViewChecked lifecycle hook ?
- How to use ngOnDestroy lifecycle hook ?