Data Binding
| Since: | Angular 14(2022) |
|---|
Data binding in Angular is the mechanism that synchronizes data between a component's TypeScript class and its HTML template. There are four main types: interpolation {{ }} (class → template, one-way), property binding [ ] (class → template, one-way), event binding ( ) (template → class, one-way), and two-way binding [( )] (bidirectional). Choosing the right binding type for each situation keeps the relationship between data and UI clear.
Binding Types
| Type | Syntax | Direction | Overview |
|---|---|---|---|
| Interpolation | {{ expression }} | Class → Template | Evaluates an expression and embeds the result as a text string in the template. |
| Property binding | [property]="expression" | Class → Template | Sets a DOM property or component input to the value of an expression. |
| Event binding | (event)="handler()" | Template → Class | Calls a method in the component class when a DOM event fires. |
| Two-way binding | [(ngModel)]="property" | Bidirectional | Keeps the template and class in sync: template changes update the class property, and class changes update the template. Requires FormsModule. |
Sample Code
Interpolation — embedding a class property as text in the template.
// greeting.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-greeting',
template: `
<h1>Hello, {{ userName }}!</h1>
<p>Score: {{ score * 2 }}</p>
<p>{{ getGreeting() }}</p>
`,
standalone: true,
})
export class GreetingComponent {
userName = 'Okabe Rintaro';
score = 42;
getGreeting(): string {
return `Welcome to the Future Gadget Lab, ${this.userName}!`;
}
}
Property binding — binding a class property to a DOM property or component input.
// image-card.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-image-card',
template: `
<img [src]="imageUrl" [alt]="imageAlt" [width]="imageWidth" />
<button [disabled]="isLoading">
{{ isLoading ? 'Loading...' : 'Submit' }}
</button>
`,
standalone: true,
})
export class ImageCardComponent {
imageUrl = '/img/sample1.jpg';
imageAlt = 'Sample image';
imageWidth = 300;
isLoading = false;
}
Event binding — calling a class method when a DOM event fires.
// click-counter.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-click-counter',
template: `
<p>Count: {{ count }}</p>
<button (click)="increment()">+1</button>
<button (click)="reset()">Reset</button>
<input (input)="onInput($event)" placeholder="Type something" />
<p>Input: {{ inputValue }}</p>
`,
standalone: true,
})
export class ClickCounterComponent {
count = 0;
inputValue = '';
increment(): void { this.count++; }
reset(): void { this.count = 0; }
onInput(event: Event): void {
this.inputValue = (event.target as HTMLInputElement).value;
}
}
Two-way binding — keeping an input field and class property in sync with [(ngModel)].
// name-input.component.ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-name-input',
template: `
<input [(ngModel)]="name" placeholder="Enter your name" />
<p>Hello, {{ name }}!</p>
`,
imports: [FormsModule],
standalone: true,
})
export class NameInputComponent {
name = '';
}
Combining all four binding types in a single interactive component.
// binding-demo.component.ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgIf } from '@angular/common';
@Component({
selector: 'app-binding-demo',
template: `
<!-- Interpolation -->
<h2>{{ title }}</h2>
<!-- Property binding -->
<input [placeholder]="placeholder" [(ngModel)]="message" />
<!-- Event binding -->
<button (click)="onSend()">Send</button>
<!-- Two-way binding result -->
<p>{{ message }}</p>
<p *ngIf="sent">Sent!</p>
`,
imports: [FormsModule, NgIf],
standalone: true,
})
export class BindingDemoComponent {
title = 'Binding Demo';
placeholder = 'Enter a message';
message = '';
sent = false;
onSend(): void {
this.sent = !!this.message;
}
}
Summary
Angular's four binding types cover all the ways data can flow between a component class and its template. Interpolation and property binding push data from the class to the view. Event binding feeds user actions back to the class. Two-way binding with [(ngModel)] handles form fields where the view and class must stay in sync.
Choose one-way bindings (interpolation or property binding) when the flow is only from class to template. Use event binding when the template needs to trigger class logic. Reserve two-way binding for form inputs where bidirectional sync is genuinely required. For more on property binding, see Property Binding. For event handling details, see Event Binding.
Common Mistake: Forgetting to import FormsModule for ngModel
Two-way binding with [(ngModel)] requires FormsModule. In standalone components, add it to imports; in NgModule-based apps, import it in the module. Without it, you will get a "Can't bind to 'ngModel'" error.
// NG: FormsModule not imported
@Component({
selector: 'app-input',
template: `<input [(ngModel)]="name" />`,
standalone: true,
})
export class InputComponent {
name = '';
}
// OK: FormsModule added to imports
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-input',
template: `<input [(ngModel)]="name" />`,
imports: [FormsModule],
standalone: true,
})
export class InputComponent {
name = '';
}
Common Mistake: Using interpolation in attribute values where property binding is needed
Interpolation ({{ }}) works for text content. For DOM properties that expect a non-string value (such as disabled or checked), use property binding ([ ]) instead.
// NG: interpolation in a boolean attribute — always evaluates to a non-empty string (truthy)
<button disabled="{{ isDisabled }}">Submit</button>
// OK: property binding correctly passes the boolean value <button [disabled]="isDisabled">Submit</button>
Common Mistake: Confusing property binding with attribute binding
Property binding ([property]) sets a DOM property. Attribute binding ([attr.attribute]) sets an HTML attribute. For standard DOM properties the two often behave the same, but for ARIA attributes or SVG that only have HTML attributes (no corresponding DOM property), attribute binding is required.
// Property binding (sets DOM property) <input [value]="userName" /> // Attribute binding (sets HTML attribute — use for aria-* and other attribute-only cases) <button [attr.aria-label]="buttonLabel">Click</button>
If you find any errors or copyright issues, please contact us.