Angular templates are HTML files enhanced with Angular-specific syntax that define component views. Templates use data binding, directives, and pipes to create dynamic user interfaces.
Template Syntax Overview
Angular templates support several types of binding syntax:
Interpolation Display component data: {{ value }}
Property Binding Set element properties: [property]="value"
Event Binding Handle events: (event)="handler()"
Two-Way Binding Combine property and event: [(ngModel)]="value"
Interpolation
Display component data in the template:
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-interpolation' ,
standalone: true ,
template: `
<h1>{{ title }}</h1>
<p>Welcome, {{ user.firstName }} {{ user.lastName }}!</p>
<p>Total: {{ price * quantity }}</p>
<p>{{ getMessage() }}</p>
`
})
export class InterpolationComponent {
title = 'My App' ;
user = { firstName: 'John' , lastName: 'Doe' };
price = 10 ;
quantity = 3 ;
getMessage () : string {
return 'Hello from method!' ;
}
}
Interpolation expressions should be simple and side-effect free. Complex logic belongs in the component class.
Property Binding
Bind component data to element properties:
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-property-binding' ,
standalone: true ,
template: `
<!-- Bind to native properties -->
<img [src]="imageUrl" [alt]="imageAlt">
<button [disabled]="isDisabled">Click Me</button>
<input [value]="inputValue" [placeholder]="placeholder">
<!-- Bind to attributes -->
<div [attr.data-id]="userId">User Info</div>
<button [attr.aria-label]="buttonLabel">Action</button>
<!-- Bind to classes -->
<div [class.active]="isActive">Status</div>
<div [class]="cssClasses">Styled</div>
<!-- Bind to styles -->
<div [style.color]="textColor">Colored Text</div>
<div [style.width.px]="width">Box</div>
<div [style]="styleObject">Styled Box</div>
`
})
export class PropertyBindingComponent {
imageUrl = 'https://angular.dev/assets/logo.png' ;
imageAlt = 'Angular logo' ;
isDisabled = false ;
inputValue = 'Initial value' ;
placeholder = 'Enter text...' ;
userId = 123 ;
buttonLabel = 'Perform action' ;
isActive = true ;
cssClasses = 'card highlighted' ;
textColor = 'blue' ;
width = 200 ;
styleObject = { color: 'red' , fontSize: '16px' };
}
Event Binding
Respond to user interactions:
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-event-binding' ,
standalone: true ,
template: `
<!-- Standard events -->
<button (click)="onClick()">Click</button>
<input (input)="onInput($event)" (blur)="onBlur()">
<form (submit)="onSubmit($event)">
<input type="text" [(ngModel)]="formValue">
<button type="submit">Submit</button>
</form>
<!-- Event with $event object -->
<input (keyup)="onKeyUp($event)">
<div (mousemove)="onMouseMove($event)">Hover me</div>
<!-- Template reference variable -->
<input #inputRef (keyup)="onKeyUpRef(inputRef.value)">
<p>Last key: {{ lastKey }}</p>
<p>Form value: {{ formValue }}</p>
`
})
export class EventBindingComponent {
lastKey = '' ;
formValue = '' ;
onClick () {
console . log ( 'Button clicked!' );
}
onInput ( event : Event ) {
const target = event . target as HTMLInputElement ;
console . log ( 'Input value:' , target . value );
}
onBlur () {
console . log ( 'Input lost focus' );
}
onSubmit ( event : Event ) {
event . preventDefault ();
console . log ( 'Form submitted:' , this . formValue );
}
onKeyUp ( event : KeyboardEvent ) {
this . lastKey = event . key ;
}
onMouseMove ( event : MouseEvent ) {
console . log ( 'Mouse at:' , event . clientX , event . clientY );
}
onKeyUpRef ( value : string ) {
console . log ( 'Value from ref:' , value );
}
}
Avoid calling methods with side effects in property bindings. Use event handlers for actions that modify state.
Two-Way Binding
Combine property and event binding:
import { Component } from '@angular/core' ;
import { FormsModule } from '@angular/forms' ;
@ Component ({
selector: 'app-two-way-binding' ,
standalone: true ,
imports: [ FormsModule ],
template: `
<input [(ngModel)]="name">
<p>Hello, {{ name }}!</p>
<input type="checkbox" [(ngModel)]="isChecked">
<p>Checked: {{ isChecked }}</p>
<select [(ngModel)]="selectedOption">
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
</select>
<p>Selected: {{ selectedOption }}</p>
`
})
export class TwoWayBindingComponent {
name = 'Angular' ;
isChecked = false ;
selectedOption = 'option1' ;
}
Control Flow
Angular provides built-in control flow syntax for conditional rendering and loops.
@if - Conditional Rendering
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-conditional' ,
standalone: true ,
template: `
<button (click)="toggle()">Toggle</button>
@if (isVisible) {
<div class="content">
<p>Content is visible!</p>
</div>
}
@if (user) {
<p>Welcome, {{ user.name }}!</p>
} @else {
<p>Please log in.</p>
}
@if (status === 'loading') {
<p>Loading...</p>
} @else if (status === 'error') {
<p class="error">Error occurred!</p>
} @else {
<p>Data loaded successfully.</p>
}
`
})
export class ConditionalComponent {
isVisible = true ;
user : { name : string } | null = { name: 'John' };
status : 'loading' | 'error' | 'success' = 'success' ;
toggle () {
this . isVisible = ! this . isVisible ;
}
}
@for - Loops
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-loops' ,
standalone: true ,
template: `
<ul>
@for (item of items; track item.id) {
<li>{{ item.name }} - {{ item.price | currency }}</li>
}
</ul>
@for (user of users; track user.id; let i = $index, first = $first) {
<div [class.first]="first">
{{ i + 1 }}. {{ user.name }}
</div>
} @empty {
<p>No users found.</p>
}
<!-- Accessing loop variables -->
@for (item of collection; track item.id; let idx = $index, count = $count) {
<div>Item {{ idx + 1 }} of {{ count }}: {{ item.name }}</div>
}
`
})
export class LoopsComponent {
items = [
{ id: 1 , name: 'Item 1' , price: 10 },
{ id: 2 , name: 'Item 2' , price: 20 },
{ id: 3 , name: 'Item 3' , price: 30 }
];
users = [
{ id: 1 , name: 'Alice' },
{ id: 2 , name: 'Bob' }
];
collection = [
{ id: 1 , name: 'First' },
{ id: 2 , name: 'Second' },
{ id: 3 , name: 'Third' }
];
}
Always provide a track expression in @for loops to help Angular identify items and optimize rendering.
@switch - Switch Statements
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-switch' ,
standalone: true ,
template: `
<select [(ngModel)]="selectedColor">
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</select>
@switch (selectedColor) {
@case ('red') {
<div class="red">You selected red!</div>
}
@case ('green') {
<div class="green">You selected green!</div>
}
@case ('blue') {
<div class="blue">You selected blue!</div>
}
@default {
<div>Select a color</div>
}
}
`
})
export class SwitchComponent {
selectedColor = 'red' ;
}
Template Reference Variables
Create local variables to reference elements:
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-template-refs' ,
standalone: true ,
template: `
<input #nameInput type="text">
<button (click)="greet(nameInput.value)">Greet</button>
<video #videoPlayer src="video.mp4"></video>
<button (click)="videoPlayer.play()">Play</button>
<button (click)="videoPlayer.pause()">Pause</button>
<form #myForm="ngForm">
<input name="email" ngModel required>
<p>Form valid: {{ myForm.valid }}</p>
</form>
`
})
export class TemplateRefsComponent {
greet ( name : string ) {
alert ( `Hello, ${ name } !` );
}
}
Safe Navigation Operator
Handle null and undefined values safely:
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-safe-navigation' ,
standalone: true ,
template: `
<!-- Without safe navigation - may cause errors -->
<p>{{ user.profile.email }}</p>
<!-- With safe navigation - safe -->
<p>{{ user?.profile?.email }}</p>
<!-- Optional with default value -->
<p>{{ user?.profile?.email ?? 'No email' }}</p>
`
})
export class SafeNavigationComponent {
user : any = null ; // May be null or undefined
}
Best Practices
Keep templates simple - Move complex logic to the component
Use track in @for - Improves performance
Avoid method calls in templates - Cache computed values
Use safe navigation - Prevent null reference errors
Prefer @if over ngIf - Modern control flow syntax
Use OnPush change detection - With immutable data patterns
Next Steps
Directives Learn about built-in and custom directives
Pipes Transform data in templates