How to manually trigger change detection in Angular
Manually triggering change detection in Angular is necessary when updates occur outside Angular’s zone or with OnPush strategy. As the creator of CoreUI with over 12 years of Angular experience since 2014, I’ve manually controlled change detection in complex applications. ChangeDetectorRef provides methods to manually trigger, detach, and reattach change detection for fine-grained control. This approach optimizes performance and ensures UI updates when Angular doesn’t automatically detect changes.
Use ChangeDetectorRef methods to manually control when Angular runs change detection cycles.
Basic manual trigger:
import { Component, ChangeDetectorRef } from '@angular/core'
@Component({
selector: 'app-manual',
template: '<div>{{ data }}</div>'
})
export class ManualComponent {
data: string
constructor(private cdr: ChangeDetectorRef) {}
updateData() {
// External update outside Angular zone
setTimeout(() => {
this.data = 'Updated'
// Manually trigger change detection
this.cdr.detectChanges()
}, 1000)
}
}
markForCheck vs detectChanges:
import { Component, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core'
@Component({
selector: 'app-comparison',
template: '<div>{{ count }}</div>',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ComparisonComponent {
count = 0
constructor(private cdr: ChangeDetectorRef) {}
// markForCheck - marks component and ancestors for check
useMarkForCheck() {
this.count++
this.cdr.markForCheck()
}
// detectChanges - runs change detection immediately
useDetectChanges() {
this.count++
this.cdr.detectChanges()
}
}
Detach and reattach:
import { Component, ChangeDetectorRef, OnDestroy } from '@angular/core'
@Component({
selector: 'app-detach',
template: `
<div>
<p>Value: {{ value }}</p>
<button (click)="toggle()">Toggle Change Detection</button>
</div>
`
})
export class DetachComponent implements OnDestroy {
value = 0
private isDetached = false
constructor(private cdr: ChangeDetectorRef) {}
toggle() {
if (this.isDetached) {
this.cdr.reattach()
console.log('Reattached')
} else {
this.cdr.detach()
console.log('Detached')
}
this.isDetached = !this.isDetached
}
ngOnDestroy() {
this.cdr.detach()
}
}
With external libraries:
import { Component, ChangeDetectorRef, OnInit, OnDestroy } from '@angular/core'
@Component({
selector: 'app-external',
template: '<div>{{ data }}</div>'
})
export class ExternalComponent implements OnInit, OnDestroy {
data: any
private subscription: any
constructor(private cdr: ChangeDetectorRef) {}
ngOnInit() {
// External library callback
window.addEventListener('customEvent', (event: any) => {
this.data = event.detail
this.cdr.detectChanges()
})
// WebSocket example
const socket = new WebSocket('ws://localhost:8080')
socket.onmessage = (event) => {
this.data = JSON.parse(event.data)
this.cdr.markForCheck()
}
}
ngOnDestroy() {
// Cleanup
}
}
Performance optimization:
import { Component, ChangeDetectorRef } from '@angular/core'
@Component({
selector: 'app-optimized',
template: `
<canvas #canvas></canvas>
<div>FPS: {{ fps }}</div>
`
})
export class OptimizedComponent {
fps = 0
private lastUpdate = Date.now()
constructor(private cdr: ChangeDetectorRef) {
this.startAnimation()
}
startAnimation() {
const animate = () => {
// Heavy canvas drawing
this.drawCanvas()
// Update FPS only every second
const now = Date.now()
if (now - this.lastUpdate > 1000) {
this.fps = Math.round(1000 / (now - this.lastUpdate))
this.lastUpdate = now
this.cdr.detectChanges()
}
requestAnimationFrame(animate)
}
requestAnimationFrame(animate)
}
drawCanvas() {
// Canvas operations
}
}
Best Practice Note
Use markForCheck() with OnPush strategy—it schedules check for next cycle. Use detectChanges() for immediate updates outside Angular zone. Detach change detection during heavy operations to improve performance. Always reattach or clean up detached components in ngOnDestroy. Use manual triggering sparingly—let Angular handle most cases automatically. This is how we handle change detection in CoreUI Angular—strategic manual triggers for external updates while relying on Angular’s automatic detection for standard operations.



