Skip to the solution
MediumFrontend8 min read

What are @ViewChild and @ContentChild?

788 views

The problem

Question presented to candidate: "What are @ViewChild and @ContentChild? Using a tabs component as the example, tell me what each one can see, when its value is available, and what the static option does."

What a strong answer should cover:

  • Both are queries: a decorator on a property that Angular fills with a match from the template.
  • @ViewChild searches the component's own template; @ContentChild searches the projected content the parent placed between its tags.
  • Timing: dynamic results are set before ngAfterViewInit / ngAfterContentInit; static: true resolves before ngOnInit but never updates, and is only valid for elements not inside @if / @for.
  • Locators: a template reference name ('title'), a component or directive class, or a provider token; read picks what to return (ElementRef, TemplateRef, ViewContainerRef, a directive).
  • A component template is a black box: content queries do not see inside other components' templates; descendants controls nested matches.
  • The signal versions viewChild() / contentChild() are the modern equivalent.

Clarifying questions expected:

  • "Is the element always rendered, or inside an @if?"
  • "Do you need the DOM element or the component instance?"

Code / implementation expected: Yes β€” a component that queries both its own template and its projected content and logs when each is available.

  • viewchild
  • queries

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

8 min read Β· 9 sections

Read the code

AngularA tab box querying its own template and its projected content
import {
  AfterContentInit, AfterViewInit, Component, ContentChild, ContentChildren, Directive,
  ElementRef, Input, QueryList, ViewChild, signal,
} from "@angular/core";

@Directive({ selector: "[tabItem]" })
export class TabItemDirective {
  @Input() tabItem = "";
}

@Component({
  selector: "tab-box",
  template: `
    <header #frame>[tab-box frame]</header>
    <ng-content />
    <ul>
      @for (line of report(); track $index) { <li>{{ line }}</li> }
    </ul>`,
})
export class TabBoxComponent implements AfterContentInit, AfterViewInit {
  // Content queries look at what the PARENT put between <tab-box> tags.
  @ContentChild("heading") heading?: ElementRef<HTMLElement>;
  @ContentChildren(TabItemDirective) direct!: QueryList<TabItemDirective>;
  @ContentChildren(TabItemDirective, { descendants: true }) all!: QueryList<TabItemDirective>;
  // View queries look only at THIS component's own template.
  @ViewChild("frame") frame?: ElementRef<HTMLElement>;
  @ViewChild("heading") headingFromView?: ElementRef<HTMLElement>;

  report = signal<string[]>([]);
  private lines: string[] = [];

  ngAfterContentInit() {
    this.lines.push(`ngAfterContentInit: @ContentChild heading = "${this.heading?.nativeElement.textContent}"`);
    this.lines.push(`ngAfterContentInit: @ViewChild frame = ${this.frame ? "ready" : "undefined (view not built yet)"}`);
    this.lines.push(`@ContentChildren default: ${this.direct.map((t) => t.tabItem).join(", ")}`);
    this.lines.push(`@ContentChildren descendants: ${this.all.map((t) => t.tabItem).join(", ")}`);
  }

  ngAfterViewInit() {
    this.lines.push(`ngAfterViewInit: @ViewChild frame = "${this.frame?.nativeElement.textContent}"`);
    this.lines.push(`ngAfterViewInit: @ViewChild heading = ${this.headingFromView ? "found" : "undefined (it is projected content)"}`);
    this.report.set(this.lines);
  }
}

@Component({
  selector: "app-root",
  imports: [TabBoxComponent, TabItemDirective],
  template: `
    <tab-box>
      <h3 #heading>Settings</h3>
      <span tabItem="general">General</span>
      <div><span tabItem="nested">Nested</span></div>
    </tab-box>`,
})
export class AppComponent {}

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 34 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

What is ComponentFixtureAutoDetect and how does it affect unit tests?

Continue