Templates and Data Binding

This section documents modern, standalone Angular — signals, the built-in @if / @for / @switch control flow, @defer, typed reactive forms, provideHttpClient, functional guards and interceptors, and server-side rendering with hydration — as described by the official documentation at angular.dev, which is the reference these pages are written and verified against.

This content was generated with the assistance of AI and should be verified against angular.dev before being relied on in production. Angular ships a major release roughly every six months and its APIs continue to evolve: the examples here target the current major release; where a consulted source disagrees with the current documentation, the documentation wins and the difference is noted.

This section’s bibliography lists the reference material consulted while preparing these pages.

An Angular template is HTML with binding syntax. Bindings connect the DOM to component state: values flow from the class into the view, and events flow from the view back into the class.

Interpolation and one-way bindings

Interpolation — {{ expression }} — inserts a stringified value into text or an attribute value. Property binding — [property]="expression" — sets a DOM property (not an attribute). Related forms target attributes, classes, and inline styles:

<h1>{{ title() }}</h1>
<p>{{ user().firstName }} {{ user().lastName }}</p>

<img [src]="avatarUrl()" [alt]="user().name" />
<button [disabled]="form.invalid">Save</button>

<td [attr.colspan]="span()">…</td>             <!-- attribute binding: no matching DOM property -->

<div [class.active]="isActive()"></div>          <!-- single class toggle -->
<div [class]="classExpr()"></div>                 <!-- string / array / Record<string, boolean> -->

<div [style.width.px]="width()"></div>            <!-- style with a unit -->
<div [style]="styleExpr()"></div>                 <!-- string or Record<string, string> -->

Use [attr.x] when there is no DOM property to bind (colspan, aria-, data-, SVG attributes). See Templates and binding.

Event binding and two-way binding

Event binding — (event)="statement" — runs a template statement when the event fires; $event is the event payload (a DOM Event, or the value a component output() emitted).

<button (click)="save()">Save</button>
<input (input)="onInput($event)" />
<div (keydown.escape)="close()"></div>          <!-- key modifier -->
<app-rating (rated)="setRating($event)" />       <!-- custom output event -->

Two-way binding — [(target)]="expr", the "banana in a box" — is shorthand for a property binding plus an event binding named targetChange. It works with ngModel on form elements and with any component that exposes a model() signal.

<!-- with ngModel (needs FormsModule in the component's imports) -->
<input [(ngModel)]="searchTerm" />

<!-- with a model() signal on a custom component -->
<app-slider [(value)]="volume" />
import { Component, model } from '@angular/core';

@Component({ selector: 'app-slider', template: `…` })
export class Slider {
  readonly value = model<number>(0);   // enables [(value)] on <app-slider>
}

Reference variables, @let, pipes, and operators

Template reference variables — #name — capture a DOM element or a component instance for use elsewhere in the same template.

@let declares a local template variable from an expression; it is re-evaluated as its dependencies change and is read-only.

<input #box (input)="search(box.value)" />
<video #player src="clip.mp4"></video>
<button (click)="player.play()">Play</button>

@let fullName = user().firstName + ' ' + user().lastName;
@let total = cart().reduce((sum, item) => sum + item.price, 0);
<p>{{ fullName }} owes {{ total | currency }}</p>

The pipe operator | transforms a value for display ({{ value | date:'short' }}); chain pipes left-to-right. The safe navigation operator ?. short-circuits to null when the left side is nullish ({{ user()?.address?.city }}), and the non-null assertion ! tells the type-checker a value is not null ({{ user()!.name }}) without emitting any runtime check.

Template expressions are a restricted subset of JavaScript. Not allowed: assignments (except = inside an event statement and [(…​)]), new, ++ / --, bitwise operators, and chained statements with ; (again, except in event statements). Expressions must have no visible side effects and should stay cheap, because they run on every change-detection pass. Angular also collapses runs of whitespace and removes whitespace between elements unless you set preserveWhitespaces. See template variables, expression syntax, and whitespace.

For the DOM event model underneath event bindings — bubbling, preventDefault(), the Event object — see browser events.