Passing data from parent to child component is trivial in Angular thanks to @Input
decorator.
In this post, I want to share how to detect @Input
value changes in Angular. This can be useful if you need to perform an action when the value of the input changes.
Using setters and getters
The easiest way to detect value changes is to implement a setter and getter for that property.
When the value of the input changes, the setter will be invoked by Angular.
This is where we can capture the new value. Here is an example:
@Component({
selector: 'child-component',
templateUrl: './child-component.component.html',
styleUrls: ['./child-component.component.css']
})
export class MyComponent {
private _myInput = '';
@Input()
set myInput(value: string) {
this._myInput = value;
// Do something with the new value
}
get myInput() {
// Return the current value of the input
return this._myInput;
}
}
Code language: JavaScript (javascript)
Every time the parent component updates myInput
, the setter in child will be called with the new value. Using the setter in the child component, we can update the its state or perform other actions based on the new value. This approach clearly indicates that you are doing something when the input property is set.
That was easy – but what’s the caveat with this approach?
While using a setter makes your code more readable and self-explanatory, it can quickly increase the complexity when there is more than three input properties. In this case, consider using the OnChanges
hook.
Using the OnChanges hook
Angular triggers OnChanges
lifecycle hook whenever the value of an input parameter changes.
It is possible to access the new and the previous value of the input property within OnChanges
. Similar to the previous approach, you can update the component state or manipulate the input value based on your needs.
Start by importing the OnChanges interface in your component:
import { Component, OnChanges } from '@angular/core';
Code language: TypeScript (typescript)
Then, decorate your component with the OnChanges interface and implement it as below:
@Component({
selector: 'child-component',
templateUrl: './child-component.component.html',
styleUrls: ['./child-component.component.css']
})
export class ChildComponent implements OnChanges {
@Input()
name: string;
ngOnChanges(changes: SimpleChanges) {
if (changes.name && changes.name.currentValue) {
// Do something
console.log(changes.name.currentValue);
}
}
}
Code language: TypeScript (typescript)
In the ngOnChanges
method above, you have access to changes
parameter. This parameter contains all properties that changed during the change detection cycle.
It’s common to use the SimpleChanges
object to check for changes in specific input properties that you are interested in. This avoids unnecessary processing for properties that haven’t changed.
SimpleChanges
type is a hashtable of SimpleChange objects. SimpleChange
object contains:
- previousValue: The previous value of the input
- currentValue: The current value of the input
- isFirstChange: Whether this is the first time the input has changed
Best practices when using OnChanges hook
Immutable data
Prefer using immutable data structures for input properties. This makes it easier to detect changes as Angular relies on object references for change detection.
Avoid complex logic
Keep the logic inside ngOnChanges
simple and focused. If complex logic is needed, extract it to a separate method or service.
Async operations
Be careful when performing asynchronous operations inside ngOnChanges
. Using other lifecycle hooks like ngOnInit
or ngAfterViewInit
can lead to more expected outcomes for async operations.
Testing
Always write unit tests to ensure that ngOnChanges
behaves as expected. You tests can cover different scenarios, including changes to multiple properties and no changes.
Conclusion
In summary, detecting changes in Angular’s @Input() values is essential for building dynamic components. We explored two approaches: using setters and getters for single inputs, and leveraging the OnChanges lifecycle hook for multiple inputs.
Hope you found this useful, see you around!