Welcome to the Angular Daily Challenge Series, where we decode real-world Angular concepts through fun and practical coding puzzles. This article dives into a common interview-level topic: OnPush change detection in Angular.
Let's analyze today's challenge and uncover the behavior of ChangeDetectorRef
and OnPush
.
β Angular OnPush Change Detection Challenge
Here's the scenario:
@Component({
selector: 'app-child',
template: `
<h1>Child Component</h1>
<span>{{ data().text }}</span>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ChildComponent {
data = input.required<{ text: string }>();
}
@Component({
template: `
<h1>Parent Component</h1>
<app-child [data]="data" />
`,
})
export class ChangeDetectionComponent {
#cdRef = inject(ChangeDetectorRef);
data = { text: 'Hello from Parent!' };
constructor() {
setTimeout(() => {
this.data.text = 'Updated from Parent!';
// Ensure the change is visible in the OnPush child
this.#cdRef.detectChanges();
}, 3_000);
}
}
β What Will Be Displayed in the Child After 3 Seconds?
β Output: "Updated from Parent!"
But why does this happen? Let's break it down with a deeper look into Angular's change detection system.
π§ How Angular OnPush Works
When you use ChangeDetectionStrategy.OnPush
, Angular skips checking the componentβs template unless one of these occurs:
- The component receives a new reference via
input
signal - An event happens inside the component
- Change detection is manually triggered using
ChangeDetectorRef
π Why Mutation Doesnβt Trigger OnPush Detection
In our example, we changed:
this.data.text = 'Updated from Parent!';
This modifies a property of the object but doesn't change the object reference, so Angular doesn't detect this change on its own.
Hence, Angular won't rerender the child unless we force it using:
this.#cdRef.detectChanges();
This is how we manually notify Angular to run change detection for all components, including OnPush
ones.
π‘ Bonus Tip: 3_000
vs 3000
in JavaScript
You might have spotted:
setTimeout(() => { ... }, 3_000);
This is JavaScript numeric separator syntax introduced in ES2021. Itβs functionally identical to 3000
, but more readable.
β Benefits:
- Easier to read large numbers (
1_000_000
,3_000
) - Especially useful for time intervals, byte sizes, and money values
β Use it in modern Angular projects, it improves code clarity without affecting performance.
π Learnings Recap
Concept | Description |
---|---|
ChangeDetectionStrategy.OnPush |
Optimizes performance by skipping change detection unless needed |
ChangeDetectorRef.detectChanges() |
Manually triggers Angularβs change detection |
Mutating object properties | Doesnβt trigger OnPush if the reference is unchanged |
3_000 in setTimeout
|
JavaScript numeric separator for better readability |
π£ Challenge for You: Can You Optimize This?
In this challenge, we manually triggered change detection. But is that always the best approach?
π Explore These Alternatives:
- β
Use immutable patterns: Replace the object entirely using
this.data = { text: 'Updated' }
- β‘ Adopt Angular Signals (Angular 17+): Better reactivity with built-in efficiency
- π§ Try markForCheck() instead of
detectChanges()
in some cases
π¬ Whatβs your go-to strategy for handling OnPush
changes? Drop your ideas and code snippets in the comments!
π Stay Connected
π¨π»βπ» Follow Rohtash Sethi π¨βπ»π₯·π for daily Angular challenges, JavaScript insights, and performance tips!
Top comments (1)
try this if you get stuck during the interview. its an AI co-pilot that solves the questions for you so you can focus on the more important part of the interview, the communication part. its also a really good study tool: ghostengineer.com__