Understanding how the Angular change detection technique helps in the process of building dynamic and responsive web applications. In this article, we’ll explore some essential concepts of Angular change detection with simple code examples.
1. Detecting Change to @Input Binding
1.1 Using a Custom Setter
In Angular, components often communicate through properties. Imagine a parent component with a counter and a child component that displays this counter. We want the child to know when the counter changes. Let’s use a custom setter for this:
@Component({
selector: 'app-child',
template: `<p>{{counter}}</p>`
})
export class ChildComponent {
_counter = 0;
@Input()
set counter(newValue: number) {
console.log("Counter updated:", newValue);
this._counter = newValue;
}
get counter() {
return this._counter;
}
}
Explanation:
The child component has a counter
property marked with @Input()
, allowing it to receive updates from the parent.
Instead of directly updating counter
, we use a special function called a custom setter (set counter(newValue: number)
) to log the update and store the value in an internal variable _counter
.
The get counter()
method is a getter that returns the stored value.
1.2 Using ngOnChanges
Another way to handle changes is by using ngOnChanges
. This method is called whenever the parent updates the counter
property:
import { Component, Input, OnChanges, SimpleChange } from '@angular/core';
@Component({...})
export class ChildComponent implements OnChanges {
@Input() counter = 0;
ngOnChanges(changes: { [key: string]: SimpleChange }) {
let c = changes;
console.log("Previous Value:", c.previousValue, "Current Value:", c.currentValue);
}
}
Explanation:
The ChildComponent
implements the OnChanges
interface and has a method called ngOnChanges
.
Whenever the parent changes the counter
, this method is called automatically.
Inside ngOnChanges
, we can access the previous and current values of the counter
.
2. Example Child and Parent Components
Now, let’s see a practical example with a parent and a child component:
@Component({
selector: 'app-child',
template: `<p>{{counter}}</p>`
})
export class ChildComponent {
@Input() counter = 0;
}
@Component({
selector: 'app-parent',
template: `<app-child [counter]="p_counter"></app-child>
<button (click)="update()">Update</button>`
})
export class ParentComponent {
p_counter = 0;
update() { this.p_counter += 1; }
}
Explanation:
The ChildComponent
has a property counter
marked with @Input()
, allowing it to receive input from the parent.
The ParentComponent
template uses <app-child [counter]="p_counter"></app-child>
to pass the value of p_counter
to the child’s counter
.
When the button is clicked, the update() the method in the parent increments p_counter
, triggering a change in the child.
3. Advanced Inter Component Communication
3.1 Direct Access to Child
3.1.1 Using a Template Local Variable
Sometimes, you need the parent to directly interact with the child without using @Input or @Output. Here’s a simple way to use a template local variable:
@Component({
selector: 'app-parent',
template: `
<app-child #ch></app-child>
<button (click)="ch.counter = ch.counter + 1">
Update</button>
`
})
export class ParentComponent {
}
Explanation:
In the parent’s template, #ch
is a local variable representing an instance of ChildComponent
.
The button click handler directly updates the counter
property of the child using this local variable.
3.1.2 Using the @ViewChild Decorator
Alternatively, we can use @ViewChild
decorator for direct access:
import { Component, ViewChild } from '@angular/core';
import { ChildComponent } from '../child/child.component';
@Component({
selector: 'app-parent',
template: `<app-child></app-child>
<button (click)="update()">Update</button>`
})
export class ParentComponent {
@ViewChild(ChildComponent, { static: false }) child: ChildComponent;
update() { this.child.counter += 1; }
}
Explanation:
The @ViewChild
decorator in the parent component allows us to access an instance of ChildComponent
.
{ static: false }
means that the child component is not static and could change during the component’s lifecycle.
The update()
method can now directly manipulate the properties or invoke methods of the child component.
Conclusion
In conclusion, these simple examples demonstrate the basics of Angular change detection. By understanding how @Input, custom setters, ngOnChanges, and direct component access work, you’re well on your way to mastering Angular component communication. As you delve deeper into Angular development, these concepts will become essential for building dynamic and efficient web applications. Happy Coding 🙂