Angular · Components

Data Binding

Data binding connects your component class to its template. Angular has four kinds, and their brackets tell you exactly which way the data flows.

Beginner 5 min Lesson 7 of 38Examples target Angular 20 with standalone components. Each lesson states the version it was verified against.
Before you start:Templates
0/38 in Angular
On this page · 5 min · Beginner

Learning objectives#

  • Name the four binding types and their syntax
  • Tell which direction each one flows
  • Combine them in one form
  • Choose the right binding for a task

Explanation#

Interpolation {{ value }} — class → view, as text.

Property binding [property]="value" — class → view, into a DOM or component property: [disabled]="isSaving", [src]="imageUrl", [price]="p.price".

Event binding (event)="handler($event)" — view → class: (click), (input), (submit), or a child component’s output.

Two-way binding [(model)]="value" — both ways at once. It is shorthand for a property binding plus an event binding. Used with ngModel in forms and with model() inputs on components.

Remember the “banana in a box” [( )]: square brackets bring data in, round brackets send events out.

Syntax#

HTML Illustrative
<p>{{ name }}</p>                       <!-- class → view (text) -->
<button [disabled]="saving">Save</button> <!-- class → view (property) -->
<button (click)="save()">Save</button>    <!-- view → class (event) -->
<input [(ngModel)]="name" />              <!-- both ways -->

Code example: All four bindings in one profile editor#

TypeScriptprofile.ts Illustrative
import { Component, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';


@Component({
  selector: 'app-profile',
  imports: [FormsModule],
  template: `
    <h2>Hello, {{ name() || 'stranger' }}!</h2>                  <!-- interpolation -->


    <img [src]="avatarUrl" [alt]="'Avatar of ' + name()" width="64" />   <!-- property -->


    <input [(ngModel)]="nameModel" (ngModelChange)="name.set($event)" placeholder="Your name" />  <!-- two-way + event -->


    <button [disabled]="!name()" (click)="save()">Save</button>  <!-- property + event -->
    @if (saved()) { <p>Saved {{ name() }} ✔</p> }
  `,
})
export class Profile {
  name = signal('');
  nameModel = '';
  saved = signal(false);
  avatarUrl = 'https://i.pravatar.cc/64';


  save() {
    this.saved.set(true);
  }
}
Expected output
The heading starts as “Hello, stranger!” and the Save button is disabled. Typing “Asha” updates the heading live and enables the button. Clicking Save shows “Saved Asha ✔”.

This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.

Step-by-step explanation#

  1. {{ name() || "stranger" }} displays text from the class.
  2. [src] and [alt] set element properties from class values.
  3. [(ngModel)] keeps nameModel and the input in sync; (ngModelChange) also copies each change into the name signal.
  4. [disabled]="!name()" enables Save only when a name exists.
  5. (click)="save()" calls a class method.

Real-world use case#

A checkout form uses interpolation for totals, property binding to disable “Pay” while saving, event binding for buttons, and two-way binding for the coupon field.

Common mistakes#

Using {{ }} inside [ ]

[src]="{{ url }}" is wrong. Inside property bindings write plain expressions: [src]="url".

Forgetting FormsModule

[(ngModel)] needs FormsModule in the component’s imports, or you get “Can’t bind to ngModel”.

Binding to attributes that are not properties

aria-* and colspan are attributes. Use [attr.aria-label]="label" for them.

Best practices#

  • Use the simplest binding that works
  • Prefer signals for component state
  • Use [attr.x] for pure HTML attributes
  • Keep event handlers as method calls

Remember this#

{{ }} and [ ] = data in. ( ) = events out. [( )] = both.

Banana in a box: [( )].

ngModel needs FormsModule.

Practice exercise#

Your task: Make a quantity picker: a number displayed with {{ }}, a "−" button disabled at 1, and a "+" button, all bound to a qty signal.

Need a hint?
[disabled]="qty() <= 1" and (click)="increase()" — templates cannot contain arrow functions, so put the update in a method.
Show solution
TypeScript Illustrative
import { Component, signal } from '@angular/core';


@Component({
  selector: 'app-qty',
  template: `
    <button [disabled]="qty() <= 1" (click)="decrease()">−</button>
    <span> {{ qty() }} </span>
    <button (click)="increase()">+</button>
  `,
})
export class Qty {
  qty = signal(1);
  increase() { this.qty.update(q => q + 1); }
  decrease() { this.qty.update(q => Math.max(1, q - 1)); }
}

Mini quiz#

Data Binding quizMultiple choice Question 1 of 3

Which syntax is event binding?

Score so far: 0/0

Want more? Practise all Angular MCQs · Angular interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.