In an Angular template, what does a #ref variable hold on a plain element, a component, an ng-template and with an exportAs name?
answer
- depends on where it is declared
- DOM node for plain elements
- instance for components
- TemplateRef for ng-template
- #x="name" picks a directive
basics
~10 sAn Angular #ref holds the DOM element on a plain element, the component instance on a component's host element, a TemplateRef on an ng-template, and the directive instance when written #x="exportAsName".
solid answer
~40 sA template reference variable, written `#name` on an element, is resolved by what it sits on. On a plain element such as `<input #search>` it is the DOM element itself, so `(click)="search.focus()"` works. On a component's host element, `<app-date-picker #start>` is the component instance, with its public members. On `<ng-template #row>` it is a `TemplateRef`, the fragment you can render elsewhere. With a value, `#f="ngForm"` or `#rla="routerLinkActive"`, it is the instance of the directive whose `exportAs` matches that name; a name no directive exports is the compile error `No directive found with exportAs`. A ref is visible to the view that declares it and to the views nested inside it.
code
html · 7 lines<form #f="ngForm" (ngSubmit)="save(f.value)">
<input name="email" ngModel required #email="ngModel" />
@if (email.touched && email.invalid) {
<p>Email is required.</p>
}
<button [disabled]="f.invalid">Save</button>
</form>go deeper
Recall the four targets: DOM element, component instance, TemplateRef, and a directive picked by its exportAs name, plus the focus-a-field example.
Explain why exportAs is needed when several directives share an element, and what compile error a wrong name gives.
Judge when a ref is fine for template-local wiring and when coupling to a component's API or reading DOM snapshots should become a query or signal.
Set a team norm: refs for local UI glue only, public component APIs kept small, and state never smuggled through DOM snapshots.
## What a template reference variable is A **template reference variable** is a name declared on an element with a hash prefix, `#name` (the long form `ref-name` also parses). It gives the rest of the template a way to reach something that exists at that spot: a DOM node, a component, a directive or a template fragment. It is a template-only name: the component class does not see it unless a query reads it. The same syntax yields **different kinds of values** depending on where it is declared: | Declared on | Example | The variable holds | |---|---|---| | a plain HTML element (or a custom element) | `<input #search>` | the DOM element (`HTMLInputElement`) | | an Angular component's host element | `<app-date-picker #start />` | the component instance | | an `<ng-template>` | `<ng-template #emptyState>` | a `TemplateRef` for that fragment | | any element, with a value | `<form #f="ngForm">` | the directive instance whose `exportAs` is `ngForm` | ## Plain elements: reaching the DOM The everyday use is calling a DOM API from an event handler without writing any class code. Focusing a search box from a button: ```ts import {Component} from '@angular/core'; @Component({ selector: 'app-search-bar', template: ` <button type="button" (click)="search.focus()">Search</button> <input #search type="search" placeholder="Find a product" /> `, }) export class SearchBar {} ``` Two details make this work: - the reference is resolved for the **whole view**, so the button may appear before the input it refers to; - the handler receives the real `HTMLInputElement`, so with strict template checks `search.focus()` is type-checked against the DOM typings. ## Components: reaching the instance When the element is a component's host, the variable is the **component instance**, not the host DOM node. That lets a sibling call a public method or read a public signal: `<app-date-picker #start />` then `<button (click)="start.clear()">`. It couples the template to that component's public API, so keep such calls to small, stable members. ## ng-template: a fragment, not an element `<ng-template>` renders nothing by itself. A reference on it is a **`TemplateRef`**, which other constructs can render later, for example as an `@if` fallback passed to a component input or through an outlet. Reading `.value` or calling DOM methods on it is a type error. ## exportAs: choosing a directive An element can carry several directives, so a bare `#x` never means "the directive". To get a directive instance you name it with the value the directive declares in `exportAs`: 1. `<form #f="ngForm">`: the `NgForm` directive, so `f.valid` and `f.value` work. 2. `<input name="email" ngModel #email="ngModel">`: the `NgModel` directive, so `email.errors` and `email.touched` work. 3. `<a routerLink="/orders" routerLinkActive="active" #rla="routerLinkActive">`: `rla.isActive`. If no directive on the element exports that name, compilation fails with `No directive found with exportAs '...'`. A directive that declares no `exportAs` cannot be referenced this way at all. ## Rules that come up in interviews - **A handle, not state**: a reference names a target for reading and calling; it is not a variable to store values in. - **One name per element**: declaring `#x` twice on the same element is a compile error (`Reference "#x" is defined more than once`); the docs also advise defining each name only once per template so the value stays predictable. - **Scoped**: a reference is visible in its own view and in nested views (inside `@if`, `@for`, `<ng-template>`), not in the parent template. - **Queries use the same names**: `viewChild('search')` can find an element by its reference name, which is the bridge from template to class. ## When not to use one A reference is a shortcut for **template-local** interaction. If the class needs the element, use a query; if the value is application state, keep it in a signal. A form value read through `#input.value` is a snapshot, not a binding, and it does not drive change detection.
- In Angular, what does #picker hold on <app-date-picker #picker> when the element also carries an attribute directive?Still the component instance. A bare `#picker` on a component's host element always resolves to the component. To reach the attribute directive instead, write `#d="exportName"` using the name that directive declares in `exportAs`; without an `exportAs`, the directive cannot be referenced from the template.
- Can the component class read an Angular #ref variable directly?Not directly: the name exists only in the template. The class reaches it through a view query such as `viewChild('search')`, which can locate an element by its reference name and return an `ElementRef`, a component or a `TemplateRef` depending on the target.
saying these in an interview costs you the question
- #ref on a component always gives the host DOM element
- A bare #ref picks whichever directive is on the element
- #ref on an ng-template refers to a comment DOM node
- Any directive can be referenced by its class name
- A #ref on a plain element holds the element's current value