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__