Data Binding
4 forms of data binding markup
Each form has a direction—to the DOM, from the DOM, or in both directions.

<li>{{hero.name}}</li> <!-- interpolation -->
<app-hero-detail [hero]="selectedHero"></app-hero-detail> <!-- property binding -->
<li (click)="selectHero(hero)"></li> <!-- event binding -->
<input [(ngModel)]="hero.name"> <!-- 2 ways data binding -->
two-way binding
You often want to both display a data property and update that property when the user makes changes.
In two-way binding, a data property value flows to the input box from the component as with property binding. The user's changes also flow back to the component, resetting the property to the latest value, as with event binding.
Angular processes all data bindings once per JavaScript event cycle, from the root of the application component tree through all child components.
two-way binding = property binding + event binding
<input [(ngModel)]="hero.name">
<!-- equals -->
<input [value]="hero.name" (input)="hero.name=$event.target.value">

That ngModel
directive hides these onerous details behind its own ngModel
input and ngModelChange
output properties.
<input [ngModel]="currentHero.name" (ngModelChange)="currentHero.name=$event">
AlthoughngModel
is a valid Angular directive, it isn't available by default. It belongs to the optionalFormsModule
and you must opt-in to using it.
The [(ngModel)]
syntax can only set a data-bound property. If you need to do something more or something different, you can write the expanded form.
The following contrived example forces the input value to uppercase:
<input [ngModel]="currentHero.name" (ngModelChange)="setUppercaseName($event)">
Customized two-way binding
The [(x)]
syntax is easy to demonstrate when the element has a settable property called x
and a corresponding event named xChange
. Here's a SizerComponent that fits the pattern. It has a size value property and a companion sizeChange event:
src/app/sizer.component.ts
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-sizer',
template: `
<div>
<button (click)="dec()" title="smaller">-</button>
<button (click)="inc()" title="bigger">+</button>
<label [style.font-size.px]="size">FontSize: {{size}}px</label>
</div>`
})
export class SizerComponent {
@Input() size: number | string;
@Output() sizeChange = new EventEmitter<number>();
dec() { this.resize(-1); }
inc() { this.resize(+1); }
resize(delta: number) {
this.size = Math.min(40, Math.max(8, +this.size + delta));
this.sizeChange.emit(this.size);
}
}
src/app/app.component.html (two-way-1)
<app-sizer [(size)]="fontSizePx"></app-sizer>
<div [style.font-size.px]="fontSizePx">Resizable Text</div>
The two-way binding syntax is really just syntactic sugar for a property binding and an event binding. Angular desugars the SizerComponent binding into this:
src/app/app.component.html (two-way-2)
<app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-sizer>
It would be convenient to use two-way binding with HTML form elements like <input>
and <select>
. However, no native HTML element follows the x
value and xChange
event pattern.
Fortunately, the Angular NgModel directive is a bridge that enables two-way binding to form elements.
Last updated
Was this helpful?