Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Components  ›  Capstone Project

ViewChild and ContentChild

ViewChild 15 minviewChild finds an element or component in a component's own template, while contentChild finds one that a parent projected into it through ng-content.

ViewChild and ContentChild

When the "Add plant" form opens, the cursor should jump into the name box. That means the component's class needs a handle on an element in the template. Angular gives you two queries, and the right one depends on who wrote the element.

The rule

viewChild finds what I wrote; contentChild finds what I was given.

viewChild searches the component's own template. Mark the element with a template reference variable (#name) and query it:

import { Component, ElementRef, viewChild } from '@angular/core';

@Component({
  selector: 'app-add-plant',
  template: `<input #nameBox placeholder="Plant name" />
             <button (click)="focusName()">Start</button>`,
})
export class AddPlant {
  nameBox = viewChild<ElementRef<HTMLInputElement>>('nameBox');

  focusName() {
    this.nameBox()?.nativeElement.focus();
  }
}

The query returns a signal. It is undefined until Angular has built the view, hence ?.. Use viewChild.required(...) when the element is always present.

contentChild searches projected content: markup a parent places between your tags, which you display with <ng-content />.

@Component({
  selector: 'app-panel',
  template: `<section>
               <button #closeBtn>Close</button>
               <ng-content />
             </section>`,
})
export class Panel {
  title = contentChild<ElementRef>('panelTitle');
}
<app-panel>
  <h2 #panelTitle>Add a plant</h2>
</app-panel>

The <h2> was written in the parent's template, so from Panel's point of view it is content, not view.

You can query a component type too: viewChild(PlantCard) returns the PlantCard instance. For many matches use viewChildren and contentChildren, which return lists. Older code writes @ViewChild('nameBox') nameBox!: ElementRef; with the same meaning.

The shortcut

Open the file where the element is typed. If it is in this component's own template, use viewChild. If it is typed in someone else's template between this component's tags, use contentChild.

Two queries in the PanelStep 1 of 3
  1. The close button

    Panel's own template has <button #closeBtn>. Written here, so viewChild('closeBtn').

The trap is using viewChild for projected content. It searches only the component's own template, so it quietly returns undefined and the focus call does nothing.

Drills

Answer fast — trust the rule.

quick drill

Panel needs its own <button #closeBtn>. Which query?

quick drill

A parent writes <app-panel><p #note>Hi</p></app-panel>. How does Panel reach #note?

quick drill

What does viewChild return in modern Angular?

quick drill

Where does projected content appear inside Panel's template?

Remember

  • viewChild finds what the component wrote; contentChild finds what a parent gave it through ng-content.
  • Both return signals that fill in after creation; use viewChildren/contentChildren for many.
  • Trap: querying projected content with viewChild gives undefined.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainView or content?

A reusable Panel component wraps any content with <ng-content /> and has its own close button. Greenhouse's 'Add plant' form uses it and puts an <input #nameBox> inside. Explain which query the Panel would use to reach its close button and which to reach nameBox, and when the results become available.