In-depth Guides
Template Syntax

Understanding template variables

Template variables help you use data from one part of a template in another part of the template. Use template variables to perform tasks such as respond to user input or finely tune your application's forms.

A template variable can refer to the following:

Syntax

In the template, you use the hash symbol, #, to declare a template variable. The following template variable, #phone, declares a phone variable with the <input> element as its value.

src/app/app.component.html

      
<h1>Template reference variables</h1>
<div>
<h2>Pass value to an event handler</h2>
<p>See console for output.</p>
<input #phone placeholder="phone number" />
<!-- lots of other elements -->
<!-- phone refers to the input element; pass its `value` to an event handler -->
<button type="button" (click)="callPhone(phone.value)">Call</button>
</div>
<hr />
<div>
<h2>Template reference variable with disabled button</h2>
<p>btn refers to the button element.</p>
<button
type="button"
#btn
disabled
[innerHTML]="'disabled by attribute: ' + btn.disabled"
></button>
</div>
<hr />
<h2>Reference variables, forms, and NgForm</h2>
<form #itemForm="ngForm" (ngSubmit)="onSubmit(itemForm)">
<label for="name">Name</label>
<input type="text" id="name" class="form-control" name="name" ngModel required />
<button type="submit">Submit</button>
</form>
<div [hidden]="!itemForm.form.valid">
<p>{{ submitMessage }}</p>
</div>
<p>JSON: {{ itemForm.form.value | json }}</p>
<hr />
<h2>Template Reference Variable Scope</h2>
<p>This section demonstrates in which situations you can access local template reference variables (<code>#ref</code>).</p>
<h3>Accessing in a child template</h3>
<!-- Accessing a template reference variable from an inner template
works as the context is inherited. Try changing the text in the
input to see how it is immediately reflected through the template
reference variable. -->
<div class="example">
<input #ref1 type="text" [(ngModel)]="firstExample" />
@if (true) {
<span>Value: {{ ref1.value }}</span>
}
</div>
<!-- In this case there's a "hidden" ng-template around the
span and the definition of the variable is outside of it. Thus, you access a template variable from a parent template (which is logical as the context is inherited). -->
<p>Here's the desugared syntax:</p>
<pre><code [innerText]="desugared1"></code></pre>
<h3>Accessing from outside parent template. (Doesn't work.)</h3>
<!-- Accessing the template reference variable from outside the parent template does
not work. The value to the right is empty and changing the
value of the input will have no effect. -->
<div class="example">
@if (true) {
<input #ref2 type="text" [(ngModel)]="secondExample" />
}
<!-- <span>Value: {{ ref2?.value }}</span> -->
<!-- uncomment the above and the app breaks -->
</div>
<p>Here's the desugared syntax:</p>
<pre><code [innerText]="desugared2"></code></pre>
<h3>*ngFor and template reference variable scope</h3>
<!-- The template is instantiated twice because *ngFor iterates
over the two items in the array, so it's impossible to define what ref2 is referencing. -->
<pre><code [innerText]="ngForExample"></code></pre>
<h3>Accessing a on an <code>ng-template</code></h3>
See the console output to see that when you declare the variable on an <code>ng-template</code>, the variable refers to a <code>TemplateRef</code> instance, which represents the template.
<ng-template #ref3></ng-template>
<button type="button" (click)="log(ref3)">Log type of #ref</button>

Refer to a template variable anywhere in the component's template. Here, a <button> further down the template refers to the phone variable.

src/app/app.component.html

      
<h1>Template reference variables</h1>
<div>
<h2>Pass value to an event handler</h2>
<p>See console for output.</p>
<input #phone placeholder="phone number" />
<!-- lots of other elements -->
<!-- phone refers to the input element; pass its `value` to an event handler -->
<button type="button" (click)="callPhone(phone.value)">Call</button>
</div>
<hr />
<div>
<h2>Template reference variable with disabled button</h2>
<p>btn refers to the button element.</p>
<button
type="button"
#btn
disabled
[innerHTML]="'disabled by attribute: ' + btn.disabled"
></button>
</div>
<hr />
<h2>Reference variables, forms, and NgForm</h2>
<form #itemForm="ngForm" (ngSubmit)="onSubmit(itemForm)">
<label for="name">Name</label>
<input type="text" id="name" class="form-control" name="name" ngModel required />
<button type="submit">Submit</button>
</form>
<div [hidden]="!itemForm.form.valid">
<p>{{ submitMessage }}</p>
</div>
<p>JSON: {{ itemForm.form.value | json }}</p>
<hr />
<h2>Template Reference Variable Scope</h2>
<p>This section demonstrates in which situations you can access local template reference variables (<code>#ref</code>).</p>
<h3>Accessing in a child template</h3>
<!-- Accessing a template reference variable from an inner template
works as the context is inherited. Try changing the text in the
input to see how it is immediately reflected through the template
reference variable. -->
<div class="example">
<input #ref1 type="text" [(ngModel)]="firstExample" />
@if (true) {
<span>Value: {{ ref1.value }}</span>
}
</div>
<!-- In this case there's a "hidden" ng-template around the
span and the definition of the variable is outside of it. Thus, you access a template variable from a parent template (which is logical as the context is inherited). -->
<p>Here's the desugared syntax:</p>
<pre><code [innerText]="desugared1"></code></pre>
<h3>Accessing from outside parent template. (Doesn't work.)</h3>
<!-- Accessing the template reference variable from outside the parent template does
not work. The value to the right is empty and changing the
value of the input will have no effect. -->
<div class="example">
@if (true) {
<input #ref2 type="text" [(ngModel)]="secondExample" />
}
<!-- <span>Value: {{ ref2?.value }}</span> -->
<!-- uncomment the above and the app breaks -->
</div>
<p>Here's the desugared syntax:</p>
<pre><code [innerText]="desugared2"></code></pre>
<h3>*ngFor and template reference variable scope</h3>
<!-- The template is instantiated twice because *ngFor iterates
over the two items in the array, so it's impossible to define what ref2 is referencing. -->
<pre><code [innerText]="ngForExample"></code></pre>
<h3>Accessing a on an <code>ng-template</code></h3>
See the console output to see that when you declare the variable on an <code>ng-template</code>, the variable refers to a <code>TemplateRef</code> instance, which represents the template.
<ng-template #ref3></ng-template>
<button type="button" (click)="log(ref3)">Log type of #ref</button>

How Angular assigns values to template variables

Angular assigns a template variable a value based on where you declare the variable:

  • If you declare the variable on a component, the variable refers to the component instance.
  • If you declare the variable on a standard HTML tag, the variable refers to the element.
  • If you declare the variable on an <ng-template> element, the variable refers to a TemplateRef instance which represents the template. For more information on <ng-template>, see How Angular uses the asterisk, *, syntax in Structural directives.

Variable specifying a name

If the variable specifies a name on the right-hand side, such as #var="ngModel", the variable refers to the directive or component on the element with a matching exportAs name.

Using NgForm with template variables

In most cases, Angular sets the template variable's value to the element on which it occurs. In the previous example, phone refers to the phone number <input>. The button's click handler passes the <input> value to the component's callPhone() method.

The NgForm directive demonstrates getting a reference to a different value by referencing a directive's exportAs name. In the following example, the template variable, itemForm, appears three times separated by HTML.

src/app/hero-form.component.html

      
<h1>Template reference variables</h1>
<div>
<h2>Pass value to an event handler</h2>
<p>See console for output.</p>
<input #phone placeholder="phone number" />
<!-- lots of other elements -->
<!-- phone refers to the input element; pass its `value` to an event handler -->
<button type="button" (click)="callPhone(phone.value)">Call</button>
</div>
<hr />
<div>
<h2>Template reference variable with disabled button</h2>
<p>btn refers to the button element.</p>
<button
type="button"
#btn
disabled
[innerHTML]="'disabled by attribute: ' + btn.disabled"
></button>
</div>
<hr />
<h2>Reference variables, forms, and NgForm</h2>
<form #itemForm="ngForm" (ngSubmit)="onSubmit(itemForm)">
<label for="name">Name</label>
<input type="text" id="name" class="form-control" name="name" ngModel required />
<button type="submit">Submit</button>
</form>
<div [hidden]="!itemForm.form.valid">
<p>{{ submitMessage }}</p>
</div>
<p>JSON: {{ itemForm.form.value | json }}</p>
<hr />
<h2>Template Reference Variable Scope</h2>
<p>This section demonstrates in which situations you can access local template reference variables (<code>#ref</code>).</p>
<h3>Accessing in a child template</h3>
<!-- Accessing a template reference variable from an inner template
works as the context is inherited. Try changing the text in the
input to see how it is immediately reflected through the template
reference variable. -->
<div class="example">
<input #ref1 type="text" [(ngModel)]="firstExample" />
@if (true) {
<span>Value: {{ ref1.value }}</span>
}
</div>
<!-- In this case there's a "hidden" ng-template around the
span and the definition of the variable is outside of it. Thus, you access a template variable from a parent template (which is logical as the context is inherited). -->
<p>Here's the desugared syntax:</p>
<pre><code [innerText]="desugared1"></code></pre>
<h3>Accessing from outside parent template. (Doesn't work.)</h3>
<!-- Accessing the template reference variable from outside the parent template does
not work. The value to the right is empty and changing the
value of the input will have no effect. -->
<div class="example">
@if (true) {
<input #ref2 type="text" [(ngModel)]="secondExample" />
}
<!-- <span>Value: {{ ref2?.value }}</span> -->
<!-- uncomment the above and the app breaks -->
</div>
<p>Here's the desugared syntax:</p>
<pre><code [innerText]="desugared2"></code></pre>
<h3>*ngFor and template reference variable scope</h3>
<!-- The template is instantiated twice because *ngFor iterates
over the two items in the array, so it's impossible to define what ref2 is referencing. -->
<pre><code [innerText]="ngForExample"></code></pre>
<h3>Accessing a on an <code>ng-template</code></h3>
See the console output to see that when you declare the variable on an <code>ng-template</code>, the variable refers to a <code>TemplateRef</code> instance, which represents the template.
<ng-template #ref3></ng-template>
<button type="button" (click)="log(ref3)">Log type of #ref</button>

Without the ngForm attribute value, the reference value of itemForm would be the HTMLFormElement, <form>. If an element is an Angular Component, a reference with no attribute value will automatically reference the component instance. Otherwise, a reference with no value will reference the DOM element, even if the element has one or more directives applied to it.

Template variable scope

Just like variables in JavaScript or TypeScript code, template variables are scoped to the template that declares them.

Similarly, Structural directives such as *ngIf and *ngFor, or <ng-template> declarations create a new nested template scope, much like JavaScript's control flow statements like if and for create new lexical scopes. You cannot access template variables within one of these structural directives from outside of its boundaries.

HELPFUL: Define a variable only once in the template so the runtime value remains predictable.

Accessing in a nested template

An inner template can access template variables that the outer template defines.

In the following example, changing the text in the <input> changes the value in the <span> because Angular immediately updates changes through the template variable, ref1.

src/app/app.component.html

      
<h1>Template reference variables</h1>
<div>
<h2>Pass value to an event handler</h2>
<p>See console for output.</p>
<input #phone placeholder="phone number" />
<!-- lots of other elements -->
<!-- phone refers to the input element; pass its `value` to an event handler -->
<button type="button" (click)="callPhone(phone.value)">Call</button>
</div>
<hr />
<div>
<h2>Template reference variable with disabled button</h2>
<p>btn refers to the button element.</p>
<button
type="button"
#btn
disabled
[innerHTML]="'disabled by attribute: ' + btn.disabled"
></button>
</div>
<hr />
<h2>Reference variables, forms, and NgForm</h2>
<form #itemForm="ngForm" (ngSubmit)="onSubmit(itemForm)">
<label for="name">Name</label>
<input type="text" id="name" class="form-control" name="name" ngModel required />
<button type="submit">Submit</button>
</form>
<div [hidden]="!itemForm.form.valid">
<p>{{ submitMessage }}</p>
</div>
<p>JSON: {{ itemForm.form.value | json }}</p>
<hr />
<h2>Template Reference Variable Scope</h2>
<p>This section demonstrates in which situations you can access local template reference variables (<code>#ref</code>).</p>
<h3>Accessing in a child template</h3>
<!-- Accessing a template reference variable from an inner template
works as the context is inherited. Try changing the text in the
input to see how it is immediately reflected through the template
reference variable. -->
<div class="example">
<input #ref1 type="text" [(ngModel)]="firstExample" />
@if (true) {
<span>Value: {{ ref1.value }}</span>
}
</div>
<!-- In this case there's a "hidden" ng-template around the
span and the definition of the variable is outside of it. Thus, you access a template variable from a parent template (which is logical as the context is inherited). -->
<p>Here's the desugared syntax:</p>
<pre><code [innerText]="desugared1"></code></pre>
<h3>Accessing from outside parent template. (Doesn't work.)</h3>
<!-- Accessing the template reference variable from outside the parent template does
not work. The value to the right is empty and changing the
value of the input will have no effect. -->
<div class="example">
@if (true) {
<input #ref2 type="text" [(ngModel)]="secondExample" />
}
<!-- <span>Value: {{ ref2?.value }}</span> -->
<!-- uncomment the above and the app breaks -->
</div>
<p>Here's the desugared syntax:</p>
<pre><code [innerText]="desugared2"></code></pre>
<h3>*ngFor and template reference variable scope</h3>
<!-- The template is instantiated twice because *ngFor iterates
over the two items in the array, so it's impossible to define what ref2 is referencing. -->
<pre><code [innerText]="ngForExample"></code></pre>
<h3>Accessing a on an <code>ng-template</code></h3>
See the console output to see that when you declare the variable on an <code>ng-template</code>, the variable refers to a <code>TemplateRef</code> instance, which represents the template.
<ng-template #ref3></ng-template>
<button type="button" (click)="log(ref3)">Log type of #ref</button>

In this case, the *ngIf on <span> creates a new template scope, which includes the ref1 variable from its parent scope.

However, accessing a template variable from a child scope in the parent template doesn't work:

      
<input *ngIf="true" #ref2 type="text" [(ngModel)]="secondExample" />
<span>Value: {{ ref2?.value }}</span> <!-- doesn't work -->

Here, ref2 is declared in the child scope created by *ngIf, and is not accessible from the parent template.

Template input variables

A template input variable is a variable with a value that is set when an instance of that template is created. See: Writing structural directives

Template input variables can be seen in action in the long-form usage of NgFor:

      
<ul>
<ng-template ngFor let-hero [ngForOf]="heroes">
<li>{{hero.name}}
</ng-template>
</ul>

The NgFor directive will instantiate this once for each hero in the heroes array, and will set the hero variable for each instance accordingly.

When an <ng-template> is instantiated, multiple named values can be passed which can be bound to different template input variables. The right-hand side of the let- declaration of an input variable can specify which value should be used for that variable.

NgFor for example also provides access to the index of each hero in the array:

      
<ul>
<ng-template ngFor let-hero let-i="index" [ngForOf]="heroes">
<li>Hero number {{i}}: {{hero.name}}
</ng-template>
</ul>

What’s next