Skip to the solution
MediumFrontend9 min read

afterRender vs afterNextRender vs ngAfterViewInit — which to use?

616 views

The problem

Question presented to candidate: "We need to initialise a third-party chart library on a div in our component and keep it in sync as data changes. Should that go in ngAfterViewInit, afterNextRender or afterRender? And is afterRender even still the right name?"

What a strong answer should cover:

  • Naming: in Angular 20+ afterRender was renamed afterEveryRender; 22.2.3 does not export afterRender at all (importing it is a compile error).
  • ngAfterViewInit is a class hook that runs during change detection, once per component, also on the server; the element exists but the app has not finished rendering.
  • afterNextRender runs once, after the whole application rendered, browser only: the right place to create the chart.
  • afterEveryRender runs after every application render: the place to push new data into the chart, preferably in a write or read phase.
  • Both render hooks must be registered in an injection context (constructor), or be given { injector }.
  • Writing a signal on every afterEveryRender causes an infinite loop (NG0103).

Clarifying questions expected:

  • "Does the app use SSR or prerendering?"
  • "Does the library need the element measured (layout), or just a node to attach to?"

Code / implementation expected: Yes — create the library object in afterNextRender, update it in afterEveryRender.

  • lifecycle
  • afterRender
  • ssr

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

9 min read · 11 sections

Read the code

AngularCreate a third-party chart in afterNextRender, keep it in sync in afterEveryRender
import { AfterViewInit, Component, ElementRef, ViewChild, afterEveryRender, afterNextRender, signal } from "@angular/core";

// Pretend this is a third-party library that needs a real DOM node.
class TinyChart {
  constructor(private host: HTMLElement) {
    host.setAttribute("data-chart", "ready");
  }
  draw(values: number[]) {
    this.host.textContent = values.map((v) => "#".repeat(v)).join(" ");
  }
}

@Component({
  selector: "app-root",
  template: `
    <div #chart class="chart"></div>
    <p>values: {{ values().join(", ") }}</p>
    <button (click)="values.set([...values(), values().length + 1])">add value</button>
    <button (click)="report.set(stats.slice())">show stats</button>
    <ul>
      @for (line of report(); track $index) { <li>{{ line }}</li> }
    </ul>`,
})
export class AppComponent implements AfterViewInit {
  @ViewChild("chart") chartEl!: ElementRef<HTMLElement>;
  values = signal([1, 2]);
  report = signal<string[]>([]);
  stats: string[] = [];
  private chart?: TinyChart;
  private renders = 0;

  constructor() {
    // Once, after the first render, in the browser only: create the library object.
    afterNextRender({
      write: () => {
        this.chart = new TinyChart(this.chartEl.nativeElement);
        this.stats.push("afterNextRender(write): chart created");
      },
    });
    // After EVERY render of the app: keep the library in sync with state.
    afterEveryRender({
      write: () => this.chart?.draw(this.values()),
      read: () => this.stats.push(`afterEveryRender(read) #${++this.renders}: chart text "${this.chartEl.nativeElement.textContent}"`),
    });
  }

  // Runs during change detection, also on the server. The element exists,
  // but this is a lifecycle hook of THIS view, not "the DOM is painted".
  ngAfterViewInit() {
    this.stats.push(`ngAfterViewInit: chart element found = ${!!this.chartEl}, chart object = ${!!this.chart}`);
  }
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 44 of 121 in Angular

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Angular questions
Up nextMedium

output() vs @Output() EventEmitter — the new signal outputs?

Continue