Skip to the solution
EasyFrontend6 min read

What are template reference variables?

634 views

The problem

Question presented to candidate: "What does #box mean in an Angular template, what value does it hold in different places, and where can you use it?"

What a strong answer should cover:

  • #name declares a template reference variable: a name for something in the template, usable elsewhere in the same template.
  • What it refers to depends on where it sits: on a plain element it is the DOM element; on a component it is the component instance; on <ng-template> it is a TemplateRef.
  • #ref="exportName" picks a directive instance by its exportAs name, for example #email="ngModel" or #f="ngForm".
  • Scope: visible anywhere in its template, but not outside an @if / @for / <ng-template> block it was declared in, and never in the component class.
  • In the class you reach the same things with viewChild() / @ViewChild queries.
  • Good use: wiring two elements together without a class field. Poor use: building business logic in the template.

Clarifying questions expected:

  • "Do you mean using it inside the template only, or getting hold of it in the class as well?"

Code / implementation expected: Yes β€” refs on an input, a component, a directive with exportAs, and ngModel.

  • template-ref

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

6 min read Β· 8 sections

Read the code

AngularRefs on an element, a component, an exportAs directive and ngModel
import { Component, Directive, signal } from "@angular/core";
import { FormsModule } from "@angular/forms";

// A directive that chooses what a #ref gets, via exportAs.
@Directive({ selector: "[appToggle]", exportAs: "toggle" })
export class ToggleDirective {
  open = signal(false);
  flip() {
    this.open.update((v) => !v);
  }
}

@Component({
  selector: "stopwatch",
  template: `<span>{{ seconds() }}s</span>`,
})
export class StopwatchComponent {
  seconds = signal(0);
  tick() {
    this.seconds.update((s) => s + 1);
  }
  reset() {
    this.seconds.set(0);
  }
}

@Component({
  selector: "app-root",
  imports: [FormsModule, StopwatchComponent, ToggleDirective],
  template: `
    <!-- 1. On a plain element: #box is the HTMLInputElement itself -->
    <input #box placeholder="type, then press Add" />
    <button (click)="add(box.value); box.value = ''; box.focus()">Add</button>
    <p>Items: {{ items().join(", ") || "none" }}</p>

    <!-- 2. On a component: #sw is the component INSTANCE, so its methods are callable -->
    <stopwatch #sw />
    <button (click)="sw.tick()">tick</button>
    <button (click)="sw.reset()">reset</button>

    <!-- 3. With a value: #t="toggle" is the directive named by exportAs -->
    <button appToggle #t="toggle" (click)="t.flip()">details</button>
    @if (t.open()) { <p>Details are open</p> }

    <!-- 4. ngModel exports itself as "ngModel", which exposes validity -->
    <input name="email" ngModel required #email="ngModel" />
    <p>email valid: {{ email.valid }}</p>
  `,
})
export class AppComponent {
  items = signal<string[]>([]);
  add(v: string) {
    if (v.trim()) this.items.update((xs) => [...xs, v.trim()]);
  }
}

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 4 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 nextEasy

How do you configure dynamic base href in Angular builds for different environments?

Continue