Skip to main content

Angular Template Variables

Angular template variables give you a direct way to access DOM elements, directives, and components within your template. They provide a simple mechanism for template-to-template communication, which can be extremely useful for performing operations without having to interact with your component class.

What are Template Variables?

A template variable is declared using a hash symbol (#) followed by a variable name. Once declared, you can reference this variable anywhere in your template to access the element's properties and methods.

Think of template variables as local variables in your template that allow you to:

  • Capture references to DOM elements
  • Access directive or component instances
  • Store template expression results

Basic Syntax

Here's how to declare a template variable:

html
<element #variableName></element>

After declaration, you can refer to the variable anywhere within the same template:

html
<button (click)="doSomething(variableName)">Do Something</button>

Capturing DOM Elements

One of the most common uses of template variables is to get a reference to DOM elements.

Example: Accessing an Input Element

html
<input #nameInput type="text" placeholder="Enter your name">
<button (click)="greet(nameInput.value)">Greet</button>
<p *ngIf="greeting">{{ greeting }}</p>
typescript
import { Component } from '@angular/core';

@Component({
selector: 'app-greet',
templateUrl: './greet.component.html'
})
export class GreetComponent {
greeting: string = '';

greet(name: string) {
this.greeting = `Hello, ${name}!`;
}
}

In this example, the #nameInput variable gives us direct access to the input element. When the button is clicked, we pass the input's value to the greet() method.

Variable Scope

Template variables are only accessible within the template that defines them. They have the following scope rules:

  • A variable is available anywhere within the template after it's been declared
  • Variables declared in structural directives (like *ngIf or *ngFor) are only available within that directive's template

Example: Scope in Structural Directives

html
<div *ngIf="isVisible; else notVisible">
<input #visibleInput placeholder="This input is visible">
<button (click)="logValue(visibleInput.value)">Log Value</button>
</div>

<ng-template #notVisible>
<p>Content is not visible</p>
</ng-template>

<!-- This will cause an error because visibleInput is only available inside the ngIf -->
<!-- <p>{{ visibleInput.value }}</p> -->

Accessing Directives and Components

Template variables aren't limited to DOM elements. You can also use them to access directive or component instances.

Example: Referencing a NgModel

html
<form>
<input [(ngModel)]="user.name" #nameModel="ngModel" name="name" required>

<div *ngIf="nameModel.invalid && nameModel.touched" class="error">
Name is required
</div>

<button type="submit" [disabled]="nameModel.invalid">Submit</button>
</form>

In this example, #nameModel="ngModel" gives us a reference to the NgModel directive applied to the input field, allowing us to check its validation state directly in the template.

Using Template Variables with ViewChild

While template variables are primarily used within templates, you can also access them in your component class using @ViewChild().

html
<input #messageInput placeholder="Enter message">
<button (click)="sendMessage()">Send Message</button>
typescript
import { Component, ElementRef, ViewChild } from '@angular/core';

@Component({
selector: 'app-message',
templateUrl: './message.component.html'
})
export class MessageComponent {
@ViewChild('messageInput') messageInputRef!: ElementRef;

sendMessage() {
const message = this.messageInputRef.nativeElement.value;
console.log('Sending message:', message);

// Clear the input after sending
this.messageInputRef.nativeElement.value = '';
}
}

Real-World Application: Custom Autocomplete Component

Let's build a simple autocomplete component that uses template variables for functionality:

html
<!-- autocomplete.component.html -->
<div class="autocomplete-container">
<input #searchInput
type="text"
(input)="onInput(searchInput.value)"
[value]="selectedItem || ''"
placeholder="Search items...">

<div class="suggestions" *ngIf="showSuggestions">
<ul>
<li *ngFor="let item of filteredItems"
(click)="selectItem(item)">
{{ item }}
</li>
</ul>
</div>
</div>
typescript
// autocomplete.component.ts
import { Component, EventEmitter, Input, Output } from '@angular/core';

@Component({
selector: 'app-autocomplete',
templateUrl: './autocomplete.component.html',
styleUrls: ['./autocomplete.component.css']
})
export class AutocompleteComponent {
@Input() items: string[] = [];
@Output() itemSelected = new EventEmitter<string>();

filteredItems: string[] = [];
selectedItem: string | null = null;
showSuggestions: boolean = false;

onInput(value: string): void {
this.showSuggestions = true;
this.filteredItems = this.items.filter(item =>
item.toLowerCase().includes(value.toLowerCase())
);
}

selectItem(item: string): void {
this.selectedItem = item;
this.showSuggestions = false;
this.itemSelected.emit(item);
}
}

Usage in a parent component:

html
<!-- parent.component.html -->
<app-autocomplete
[items]="countries"
(itemSelected)="onCountrySelected($event)">
</app-autocomplete>

<p *ngIf="selectedCountry">You selected: {{ selectedCountry }}</p>
typescript
// parent.component.ts
import { Component } from '@angular/core';

@Component({
selector: 'app-parent',
templateUrl: './parent.component.html'
})
export class ParentComponent {
countries = ['USA', 'Canada', 'UK', 'Germany', 'France', 'Japan', 'Australia'];
selectedCountry: string | null = null;

onCountrySelected(country: string): void {
this.selectedCountry = country;
console.log('Country selected:', country);
}
}

In this example, we use the #searchInput template variable to access the input's value when the user types, without having to explicitly set up two-way binding.

Advanced Usage: Template Variable Assignment

You can assign a variable name explicitly to specify which value to capture:

html
<form #ngForm="ngForm">
<!-- Now ngForm refers to the NgForm directive instance, not the form element -->
</form>

This is especially useful when working with directives that expose specific APIs.

Summary

Template variables in Angular provide a powerful way to:

  • Directly access DOM elements within templates
  • Reference directives and component instances
  • Pass data between parts of your template without going through the component class
  • Simplify common interaction patterns, like form handling and user inputs

Remember that template variables have scope limitations - they're only available within their declaring template, and only after their point of declaration.

Additional Resources

Exercises

  1. Create a simple form with multiple fields and use template variables to validate and display error messages without using FormGroup/FormControl.

  2. Build a tabbed interface component where each tab panel is only initialized when selected, using template variables to track the active tab.

  3. Create a dynamic list component with template variables that allow for item selection, editing, and deletion directly from the template.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)