
Angular handles most change detection automatically — from button clicks to HTTP calls — so most of the time, you don’t have to think about it. But sometimes, you need full control.
Maybe you’re integrating a third-party library, using Web Workers, or optimizing a high-performance app. In such cases, triggering change detection manually can give you that extra edge.
Let’s break down the when, why, and how of manual change detection using Angular’s ChangeDetectorRef
and ApplicationRef
.
🤔 Why Trigger Change Detection Manually?
Angular’s automatic change detection usually kicks in just fine. But in certain advanced situations, you may want to manually trigger it:
- You’re running code outside Angular’s zone (like
runOutsideAngular()
or a third-party script) - You’ve opted into OnPush change detection for performance reasons
- You’re using custom event sources (WebSockets,
setInterval
, etc.) - You want to avoid unnecessary re-renders and decide exactly when updates happen
That’s where Angular’s low-level tools come in.
🔧 Option 1: ChangeDetectorRef
— Component-Level Control
The ChangeDetectorRef
service gives you precise control over a component’s change detection — and everything inside it.
✅ Best Use: When updating part of the component tree
Example:
import { Component, ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'app-manual',
template: `<p>{{ counter }}</p> <button (click)="update()">Update</button>`
})
export class ManualComponent {
counter = 0;
constructor(private cdRef: ChangeDetectorRef) {}
update() {
setTimeout(() => {
this.counter++;
this.cdRef.detectChanges(); // Triggers change detection manually
}, 0);
}
}
💡 Useful ChangeDetectorRef
Methods
Method | What It Does | When to Use It |
---|---|---|
detectChanges() | Manually runs change detection on the component & children | After changes outside Angular |
markForCheck() | Marks component for checking on next tick (for OnPush ) | When updating @Input() from outside Angular |
detach() | Removes component from Angular’s change detection tree | To pause updates and improve performance |
reattach() | Reconnects the component back to change detection | When you’re ready to resume UI updates |
🚀 Option 2: ApplicationRef
— App-Wide Detection
Need to update your entire app instead of just one component? That’s where ApplicationRef
comes in.
✅ Best Use: Global state changes, time-based updates, etc.
Example:
import { ApplicationRef, Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `<p>{{ now }}</p>`
})
export class AppComponent {
now = new Date().toLocaleTimeString();
constructor(private appRef: ApplicationRef) {
setInterval(() => {
this.now = new Date().toLocaleTimeString();
this.appRef.tick(); // Triggers app-wide change detection
}, 1000);
}
}
⚠️ Important: appRef.tick()
is powerful — but expensive. It runs change detection for the whole app, so use it sparingly.
🚫 When NOT to Use Manual Change Detection
While it’s tempting to take control, manual change detection should be the exception — not the norm.
Avoid if:
- You can use Angular’s signals or reactive patterns
- You’re just trying to “force” UI updates without fixing the root cause
- It makes your component harder to test or debug
✅ Use signals
in Angular 16+ whenever possible. They’re reactive, automatic, and far more maintainable.
🧠 Pro Tips for Manual Detection
- Use
markForCheck()
withChangeDetectionStrategy.OnPush
for smarter updates - Detach change detection on heavy components and reattach only when needed
- Combine
ChangeDetectorRef
withNgZone.runOutsideAngular()
for background work - Use
ApplicationRef.tick()
only for global state sync — not for everyday updates
✅ Final Thoughts
Manual change detection is one of Angular’s most advanced tools — and when used correctly, it’s a performance superpower. Whether you’re integrating third-party libraries, working with custom event sources, or optimizing updates, mastering ChangeDetectorRef
and ApplicationRef
will give you precision over your UI.
But remember — with great power comes great responsibility. Use these tools wisely, keep your code maintainable, and let Angular do the heavy lifting when it can.
Ready to build faster, cleaner Angular apps? You’re in full control now. 💪