Angular's ChangeDetectorRef: Manually Triggering Updates

Angular's `ChangeDetectorRef` is your manual override for change detection. Use it when updates from outside Angular's zone (like third-party libraries) don't refresh the UI. The footgun is overuse, which can mask performance issues or cause lifecycle errors.
WHY IT EXISTS Angular uses Zone.js to automatically detect when application state changes and update the view. It does this by patching asynchronous browser APIs like setTimeout or event listeners. However, if a change occurs via a mechanism that Zone.js doesn't patch (like a third-party library's callback), Angular remains unaware, and the UI and data model fall out of sync. ChangeDetectorRef provides the manual link to bridge this gap.
THE MENTAL MODEL Think of ChangeDetectorRef as a direct line to a specific component's change detector. Normally, Angular runs change detection for the entire component tree from the top down. ChangeDetectorRef lets you grab one component's detector and command it directly, saying "run yourself now" or "mark yourself as needing a check." It's a scalpel for fine-grained control when the automatic system isn't sufficient.
HOW IT WORKS You inject ChangeDetectorRef into a component's constructor. It exposes several key methods. The two most common are: first, detectChanges(), which immediately runs change detection on the component and its children; and second, markForCheck(), which marks the component and its ancestors as "dirty," so they will be checked during the next regular change detection cycle. markForCheck() is often safer and more performant, especially with the OnPush strategy.
WHEN TO USE IT The primary use case is integrating with code that runs outside Angular's zone. This includes handling events from third-party libraries, WebSocket messages, or even a plain setTimeout callback. It is also essential when using the OnPush change detection strategy. With OnPush, Angular only checks a component if its inputs change, so you must use markForCheck() to signal that an internal state change requires a UI update.
WHEN NOT TO USE IT Avoid using it as a hammer for every update problem. Frequent manual calls often signal a deeper architectural issue or a misunderstanding of Angular's data flow. Calling detectChanges() excessively can hurt performance. A major footgun is calling it within certain lifecycle hooks like ngAfterViewInit, which can easily trigger the infamous ExpressionChangedAfterItHasBeenCheckedError because you are changing a value after Angular has already finished its check for the current cycle.
ONE CANONICAL EXAMPLE A component property is updated inside a setTimeout callback. Because Zone.js patches setTimeout, this usually works automatically. But if you were using an un-patched async library, the view would not update. To fix this, you would inject ChangeDetectorRef (as cdr) and call this.cdr.detectChanges() within the callback, forcing Angular to re-render the component with the new data.
Read the original → angular.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.