Key Takeaways
ngAfterViewCheckedruns after Angular checks a component's view and its child views, including the initial check.- It reports completion of a check, not whether anything changed or whether Angular missed an update.
- Keep the hook cheap: frequent checks can make repeated computation, DOM access, and requests expensive.
- Don't change already-checked bound state here. Prefer bindings for UI updates and render callbacks for necessary DOM work.
Angular ngAfterViewChecked is a lifecycle hook called after a component's view has been checked for changes. Use it sparingly when you specifically need that notification—not as a general change detector or a signal that the entire page has finished rendering.
Understanding ngAfterViewChecked
A view check is Angular evaluating a component's template bindings and checking the relevant child views for updates. A check can complete without changing any rendered value; ngAfterViewChecked() receives no arguments and provides no change record.
For a component, ngAfterViewChecked follows ngAfterContentChecked. The distinction is between projected content and the component's own template; see the ngAfterContentChecked example for the content side of that lifecycle.
Initial view check:
view and child views checked
-> ngAfterViewInit (once per component instance)
-> ngAfterViewChecked
Subsequent applicable view checks:
view and child views checked
-> ngAfterViewChecked
At these after-view hooks: don't mutate already-checked bound state.There is no fixed invocation rate. Events elsewhere in the application can lead to checks even when this component's data hasn't changed, while OnPush can skip eligible subtrees. Scheduling also depends on your change-detection configuration; in zoneless applications, notifications such as bound listeners and updates to template-read signals tell Angular when to check.
Angular ngAfterViewChecked Example
In an existing standalone Angular application, save this as home.component.ts. Import HomeComponent into its parent, add it to the parent's imports array, and render <app-home></app-home> in that parent's template.
import { Component, type AfterViewChecked } from '@angular/core';
@Component({
selector: 'app-home',
standalone: true,
template: `
<button type="button" (click)="clickMe()">
Click me: {{ clicks }}
</button>
`,
})
export class HomeComponent implements AfterViewChecked {
clicks = 0;
private lastLoggedClicks: number | undefined;
ngAfterViewChecked(): void {
if (this.clicks === this.lastLoggedClicks) {
return;
}
// Diagnostic bookkeeping only; no binding reads this field.
this.lastLoggedClicks = this.clicks;
console.log('after view checked', this.clicks);
}
clickMe(): void {
this.clicks += 1;
console.log('button clicked');
}
}The first check logs the initial count. Clicking the button updates clicks in the event handler; the hook then logs the checked value. The equality guard suppresses duplicate messages, not hook invocations.
The optional AfterViewChecked interface describes ngAfterViewChecked(): void; Angular calls the correctly named method whether or not you implement that interface. Implementing it gives TypeScript an opportunity to catch a misspelled or incompatible method. You don't need OnInit to use this hook.
This is a diagnostic example, not a recommended way to react to the counter changing. In normal application code, handle that work in the event or state flow and omit the hook.
When and Why to Use ngAfterViewChecked
Use this hook only when the requirement is specifically to observe completion of this view's checks. Temporary lifecycle diagnostics are a reasonable example. Don't add it merely because something needs to happen “after a change.”
Choose the mechanism that matches the actual requirement:
| Requirement | Better starting point |
|---|---|
| Update displayed values or styles | Template bindings, directives, and CSS |
| React to changed component inputs | ngOnChanges |
| Access initialized view-query results once | ngAfterViewInit |
| Access rendered DOM once | afterNextRender |
| Access rendered DOM after repeated application renders | afterEveryRender, with guards against unnecessary work |
These timings aren't interchangeable: ngAfterViewInit is a one-time view-initialization hook, while render callbacks run after Angular finishes rendering the application's components into the DOM.
Don't use ngAfterViewChecked as a catch-all for animations, error handling, or third-party integrations. For ordinary visual changes, start with bindings and CSS; for an integration that needs rendered DOM, start with a render callback.
Cautions and Considerations
Don't mutate already-checked bound state
Changing a value used by an already-checked binding inside ngAfterViewChecked can produce ExpressionChangedAfterItHasBeenCheckedError. Angular throws this error in development mode when its additional verification detects that an expression changed after change detection completed.
Move the update to initialization, an input-change handler, or the event that causes it. Don't treat production mode hiding the error as a fix, or force another check from inside this hook to conceal an ordering problem.
The example's private logging field is different: no template binding reads it. That bookkeeping doesn't change the rendered state.
Use render callbacks for necessary DOM access
Angular recommends render callbacks rather than other lifecycle hooks for direct DOM access. Repeated layout reads and writes during view checks can cause layout thrashing—unnecessary repeated browser layout work.
If you genuinely need an element's dimensions, measure it after rendering rather than after every view check. Use this component through its app-measured-panel selector, importing it into its parent as in the previous example:
import {
afterNextRender,
Component,
type ElementRef,
viewChild,
} from '@angular/core';
@Component({
selector: 'app-measured-panel',
standalone: true,
template: `<section #panel>Content to measure</section>`,
})
export class MeasuredPanelComponent {
private readonly panel =
viewChild.required<ElementRef<HTMLElement>>('panel');
constructor() {
afterNextRender({
read: () => {
const { width, height } =
this.panel().nativeElement.getBoundingClientRect();
console.log('Panel dimensions:', { width, height });
},
});
}
}afterNextRender registers work for the next completed application render; afterEveryRender registers repeated work. They are functions, not component lifecycle methods, and should be registered in an injection context, such as a component constructor.
Put layout-affecting writes in the write phase and measurements in read; Angular runs write before read. Prefer explicit phases instead of mixing reads and writes.
Keep HTTP requests out of the check loop
Don't initiate a request on each view check. Each subscription to an HttpClient request observable sends a new backend request, so subscribing inside this hook can issue duplicates. Start loading through an appropriate ngOnInit initialization flow or user action, with cancellation or deduplication where needed. Unsubscribing aborts an in-progress request.
Common Mistakes
- Treating a check as a change: the hook doesn't tell you what changed, or whether a binding changed at all.
- Moving expensive work behind an expensive guard: comparing a primitive is cheap; scanning a large collection on every check still adds work.
- Replacing one repeated hook with another:
afterEveryRenderimproves DOM timing, but repeated work still needs a reason and a guard.
If performance is the reason you're investigating this hook, measure first. Angular DevTools can show time spent evaluating templates and lifecycle hooks; Angular's slow-computation guide explains how to identify that cost.
FAQ
When does Angular call ngAfterViewChecked, and how often?
Angular calls ngAfterViewChecked after the component's view and child views have been checked, including the initial check. It has no fixed frequency; application activity and change-detection configuration determine when applicable checks happen.
What is the difference between ngAfterViewInit and ngAfterViewChecked?
ngAfterViewInit runs once after the initial view check and initialization. ngAfterViewChecked also runs after that initial check and after subsequent applicable view checks.
Can changing state in ngAfterViewChecked cause ExpressionChangedAfterItHasBeenCheckedError?
Yes. Changing a value used by an already-checked binding can produce this development-mode error; move the update to initialization, an input-change handler, or an event flow instead.
Should I use ngAfterViewChecked for DOM manipulation?
Prefer bindings and directives for ordinary UI updates. For necessary DOM access, use afterNextRender for one render or afterEveryRender for repeated render callbacks, with explicit read/write phases.
Can I perform HTTP requests in ngAfterViewChecked?
Don't initiate requests on each view check: repeated subscriptions can produce duplicate requests. Start loading during an appropriate initialization or user-action flow, with cancellation or deduplication where needed.
Further Reading
- AfterViewChecked API — the interface and method signature.
- Angular component lifecycle — hook timing, optional interfaces, and render callbacks.
- afterNextRender API — one-time callbacks, phases, and hydration caveats.
- afterEveryRender API — repeated callbacks and phase ordering.
- Using DOM APIs in Angular — when direct DOM access is appropriate.
- ExpressionChangedAfterItHasBeenCheckedError — why development-mode verification fails.
- Skipping component subtrees — how OnPush affects checks.
- Making HTTP requests — subscriptions, duplicate requests, and cancellation.
