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.
The close button
Panel's own template has<button #closeBtn>. Written here, soviewChild('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.
Panel needs its own <button #closeBtn>. Which query?
A parent writes <app-panel><p #note>Hi</p></app-panel>. How does Panel reach #note?
What does viewChild return in modern Angular?
Where does projected content appear inside Panel's template?
Remember
viewChildfinds what the component wrote;contentChildfinds what a parent gave it throughng-content.- Both return signals that fill in after creation; use
viewChildren/contentChildrenfor many. - Trap: querying projected content with
viewChildgivesundefined.
