Angular Data Binding
Data binding connects your component's state to the template.
Data Binding Essentials
- Connect component state and template markup.
- Use interpolation for text, property binding for DOM properties, and event binding for user actions.
- Use two-way binding for form inputs that both display and update state.
- Bind attributes with
[attr.*], and classes/styles with[class.*]/[style.*].
{{ value }}
[prop]="value"
(event)="handler($event)"
[(ngModel)]="value"
Notes:
- Related: See Templates for interpolation basics, Events for handling user input, and Conditional Rendering to show/hide content based on state.
- For two-way binding with
ngModel, importFormsModule.
Basic Data Binding
Interpolation:{{ value }}prints text.Property binding:[prop]="value"sets element/DOM properties.Event binding:(event)="handler($event)"listens to user actions.
{{ name }}
[value]="name"
(input)="name = $any($event.target).value"
Example
Bind values and handle events to keep the view in sync with component state:
Example
import { bootstrapApplication } from '@angular/platform-browser';
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
standalone: true,
template: `
<h3>Data Binding</h3>
<input [value]="name" (input)="name = $any($event.target).value" placeholder="Type your name">
<p>Hello {{ name }}!</p>
<button (click)="count = count + 1">Clicked {{ count }} times</button>
<button [disabled]="isDisabled">Can't click me</button>
`
})
export class App {
name = 'Angular';
count = 0;
isDisabled = true;
}
bootstrapApplication(App);
<app-root></app-root>
Example explained
{{ name }}: Interpolation prints the currentnamevalue as text.[value]="name": Property binding sets the input's value from the component state.(input)="name = $any($event.target).value": Event binding updatesnamefrom the input's current text.(click)="count = count + 1": Increments thecountfield when the button is clicked.[disabled]="isDisabled": Disables the button whenisDisabledis true.
Notes:
Keep expressions light:Avoid heavy work in{{ ... }}; compute in the component.No side effects:Don't mutate state or call state-changing functions inside bindings.Accessibility:If you disable elements, communicate why (e.g., helper text or ARIA) so users aren't confused.
Two-way Binding
- Sync template and component: page ↔ component.
- Use
[(ngModel)]for form controls. - Conceptually equals
[value]+(input). - Requires
FormsModule.
<input [(ngModel)]="name">
Example
Use [(ngModel)] to read and update form values:
Example
import { bootstrapApplication } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, FormsModule],
template: `
<h3>Two-way Binding (ngModel)</h3>
<label>
Name: <input [(ngModel)]="name" placeholder="Type your name" />
</label>
<label style="margin-left:12px">
Favorite:
<select [(ngModel)]="favorite">
<option value="Angular">Angular</option>
<option value="TypeScript">TypeScript</option>
<option value="JavaScript">JavaScript</option>
</select>
</label>
<p>Hello {{ name || 'friend' }}!</p>
<p>Favorite: {{ favorite }}</p>
`
})
export class App {
name = 'Angular';
favorite = 'Angular';
}
bootstrapApplication(App);
<app-root></app-root>
Example explained
[(ngModel)]="name": Two-way binds the input to thenamefield (requiresFormsModule).[(ngModel)]="favorite": Keeps theselectand thefavoritefield in sync.- Concept: Equivalent to
[value]plus(input)wiring under the hood.
Note: [(ngModel)] won't work unless FormsModule is imported.
Attribute Binding
- Some values are attributes, not DOM properties (e.g.,
colspan). - Use
[attr.*]when no property exists. - Use
[class.*]and[style.*]for classes and styles.
[attr.colspan]="span"
[class.active]="isActive"
[style.color]="color"
Example
Bind attributes, classes, and styles from component state:
Example
import { bootstrapApplication } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule],
styles: [`
table { border-collapse: collapse; margin-top: 10px; }
th, td { border:1px solid #ccc; padding:8px 10px; }
.toolbar { display:flex; gap:10px; align-items:center; }
`],
template: `
<h3>Attribute Binding (attr.*)</h3>
<div class="toolbar">
<label>Colspan: <input type="range" min="1" max="3" [value]="span" (input)="span = +$any($event.target).value"> {{ span }}</label>
<label>Title: <input [value]="title" (input)="title = $any($event.target).value"></label>
</div>
<table [attr.title]="title">
<thead>
<tr><th>A</th><th>B</th><th>C</th></tr>
</thead>
<tbody>
<tr>
<td [attr.colspan]="span" style="background:#f9fbff">colspan={{ span }}</td>
<td *ngIf="span < 2">B</td>
<td *ngIf="span < 3">C</td>
</tr>
</tbody>
</table>
`
})
export class App {
span = 1;
title = 'Data table';
}
bootstrapApplication(App);
<app-root></app-root>
Example explained
[attr.title]="title": Sets the table'stitleattribute from thetitlefield.[attr.colspan]="span": Binds the cell'scolspanattribute to the number inspan.- Range input: Adjusts
spanby reading$event.target.value; the template reflects the change. - Conditional cells:
*ngIfshows/hides extra columns based on the currentspan.
Note: Use property binding when available; use [attr.*] only when no property exists (e.g., colspan).