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:
<element #variableName></element>
After declaration, you can refer to the variable anywhere within the same template:
<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
<input #nameInput type="text" placeholder="Enter your name">
<button (click)="greet(nameInput.value)">Greet</button>
<p *ngIf="greeting">{{ greeting }}</p>
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
<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
<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()
.
<input #messageInput placeholder="Enter message">
<button (click)="sendMessage()">Send Message</button>
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:
<!-- 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>
// 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:
<!-- parent.component.html -->
<app-autocomplete
[items]="countries"
(itemSelected)="onCountrySelected($event)">
</app-autocomplete>
<p *ngIf="selectedCountry">You selected: {{ selectedCountry }}</p>
// 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:
<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
-
Create a simple form with multiple fields and use template variables to validate and display error messages without using FormGroup/FormControl.
-
Build a tabbed interface component where each tab panel is only initialized when selected, using template variables to track the active tab.
-
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! :)