Blog

ngAfterViewInit Example | Angular

Key Takeaways

  • ngAfterViewInit runs once per component instance after Angular initializes its view and view children.
  • Use it to read initialized view queries, not as a guarantee that the browser has painted or asynchronous content has finished loading.
  • Prefer template bindings for ordinary UI updates and render callbacks for imperative DOM work.
  • View queries can change later, but those changes don't run ngAfterViewInit again.

Angular calls ngAfterViewInit once after a component's view and its view children have been initialized. It's the lifecycle hook for initialization that needs an available view query, such as a reference to a child component or template element.

The important distinction is view initialization, not completed browser rendering. When your operation actually reads or changes the DOM, Angular recommends render callbacks rather than performing that work inside this hook.

Angular ngAfterViewInit Example with @ViewChild

This component keeps the original example's #myDiv reference, but uses strict TypeScript typing and lets a template binding handle text updates.

// home.component.ts — component fragment for an existing Angular app.
import {
  AfterViewInit,
  Component,
  ElementRef,
  ViewChild,
} from '@angular/core';

@Component({
  selector: 'app-home',
  standalone: true,
  template: `
    <div #myDiv>{{ message }}</div>
    <button type="button" (click)="updateText()">Update text</button>
  `,
})
export class HomeComponent implements AfterViewInit {
  @ViewChild('myDiv') myDiv!: ElementRef<HTMLDivElement>;

  message = 'Initial Text';

  ngAfterViewInit(): void {
    console.log('View child available:', this.myDiv);
  }

  updateText(): void {
    this.message = 'Text after view init';
  }
}

#myDiv is a template reference variable. @ViewChild('myDiv') retrieves its reference; with the default static: false setting, Angular resolves the query before calling ngAfterViewInit. The element is unconditional here, so the reference is available when the hook runs.

The ! is TypeScript's definite assignment assertion: it tells the compiler that the field will be initialized outside the constructor. It satisfies strictPropertyInitialization, but it doesn't add a runtime check or make a missing child exist.

Clicking the button updates message, and Angular updates the displayed text through interpolation. The hook doesn't run again. Unlike assigning to nativeElement.textContent, this keeps the text update in Angular's template model.

When Should You Use ngAfterViewInit?

Use ngAfterViewInit when one-time initialization needs a query result. For example, you might inspect a queried child component's public configuration after that child has initialized. If your task instead needs browser geometry, focus, or a native-element integration, use a render callback.

The Angular lifecycle guide distinguishes component initialization hooks from application-wide render callbacks:

Hook or callbackWhen it runsBest fit
ngOnInitOnce, after initial inputs are initialized and before the component's own template is initialized.Set initial state from inputs.
ngAfterViewInitOnce, after the component's view is initialized.Read initialized view queries.
afterNextRenderOnce, after the next application render completes.One-time imperative DOM initialization.
afterEveryRenderAfter each application render completes.DOM synchronization that genuinely needs repeated execution.

For input-dependent setup, see the Angular ngOnInit example. Don't delay ordinary state initialization until the view hook unless it actually depends on a view query.

Simplified initial lifecycle — other hooks omitted:

Initial inputs initialized
        |
        v
ngOnInit
        |
        v
Component view and view children initialized
        |
        v
ngAfterViewInit — read initialized view queries
        |
        v
Angular finishes rendering the application into the DOM
        |
        v
Registered afterNextRender / afterEveryRender callbacks

Browser paint is a separate concern.

Use afterNextRender for DOM-Dependent Initialization

afterNextRender lets you register one-time work after Angular finishes its next render. Register it in an injection context, typically the component constructor; Angular runs the callback on browser platforms, not during server-side rendering or build-time prerendering.

For example, measure an element in the callback's read phase rather than in ngAfterViewInit:

// measured-panel.component.ts — component fragment for an existing Angular app.
import {
  afterNextRender,
  Component,
  ElementRef,
  viewChild,
} from '@angular/core';

@Component({
  selector: 'app-measured-panel',
  standalone: true,
  template: `<div #panel>Panel content</div>`,
})
export class MeasuredPanelComponent {
  readonly panel = viewChild.required<ElementRef<HTMLDivElement>>('panel');

  constructor() {
    afterNextRender({
      read: () => {
        const width = this.panel().nativeElement.getBoundingClientRect().width;
        console.log('Panel width:', width);
      },
    });
  }
}

This is an exceptional imperative operation: it asks the browser for geometry rather than updating ordinary UI text. For callbacks that modify the DOM, use the write phase; keeping layout reads and writes separate helps avoid layout thrashing.

Use the same post-render boundary for third-party charts, editors, or animation libraries that need native elements. Follow the library's initialization requirements, and release its resources when the component is destroyed; the Angular ngOnDestroy example covers cleanup.

Neither lifecycle timing nor a one-time render callback waits for your application's asynchronous data. Coordinate data-dependent initialization with the data's actual readiness. Use afterEveryRender only when repeated post-render work is necessary, not as a polling substitute.

Conditional ViewChild Queries Can Change Later

If the target is inside @if, it may not exist when ngAfterViewInit runs. A dynamic query updates as matching children appear, disappear, or change, but the hook itself still runs only once for that component instance.

For decorator queries, use a @ViewChild setter to handle reference changes, or subscribe to QueryList.changes for a @ViewChildren collection. Angular recommends signal-based viewChild and viewChildren queries for new projects; their results stay up to date, and an optional viewChild returns undefined when there's no match. Decorator queries remain supported.

Don't replace query-change handling with constant checking in ngAfterViewChecked. That hook runs frequently and can affect performance.

Common Mistakes

  • Changing already-checked template state in the hook. This can trigger ExpressionChangedAfterItHasBeenCheckedError in development mode. Initialize ordinary state earlier, usually in a field initializer or ngOnInit; direct DOM mutation isn't a general workaround. See Angular's NG0100 debugging guidance.
  • Using static: true just to access a conditional child earlier. Static queries are available in ngOnInit, but their results don't update after initialization. Use them only for targets that are always present.
  • Treating ! as a runtime guarantee. It changes TypeScript's checking, not Angular's query behavior. Represent an optional child as optional and handle its absence.

FAQ

When does ngAfterViewInit run?

Angular calls ngAfterViewInit once per component instance after its view and view children have been initialized. It lets you read initialized view queries, but it doesn't guarantee browser paint or asynchronous data completion.

Does ngAfterViewInit run every time data or a child view changes?

No. Data changes and changing view-query results don't rerun ngAfterViewInit; destroying and recreating the component creates a new instance whose hook runs once.

How does ngAfterViewInit differ from ngOnInit?

ngOnInit runs after Angular initializes the component's initial inputs and before its own template is initialized; ngAfterViewInit runs after its view is initialized. Default dynamic @ViewChild queries are available by ngAfterViewInit, while static: true queries are available in ngOnInit but don't update later.

Should I use ngAfterViewInit or afterNextRender for DOM access?

Use ngAfterViewInit to read initialized view-query results and afterNextRender for imperative DOM operations after Angular renders. Render callbacks don't run during server-side rendering and don't guarantee that components have been hydrated.

Can changing component state in ngAfterViewInit cause ExpressionChangedAfterItHasBeenCheckedError?

Yes. Changing an already-checked template binding in ngAfterViewInit can trigger this development-mode error; initialize ordinary state earlier rather than bypassing Angular with direct DOM mutation.

Further Reading

Written by Sam Erickson

Software engineer. I write every article on StackChief myself. Author of Mastering the Tech Interview. More about me