Two-way Binding
The "Edit plant" form has a nickname box and a water-level slider. When the class changes the value, the field should show it; when the user types or drags, the class should know. That is data flowing both ways, and Angular has a shorthand for it.
The rule
Banana in a box:
[( )]is a binding in plus an event out.
The shape [( )] looks like a banana inside a box, which is how most people remember the order: brackets outside, parentheses inside.
It is pure shorthand. For a property called level, Angular expands
<app-water-slider [(level)]="waterLevel" />into a property binding and an event binding whose name is the property plus Change:
<app-water-slider [level]="waterLevel()" (levelChange)="waterLevel.set($event)" />On your own components, declare the property with model(). It creates the input and the matching levelChange output in one go:
import { Component, model } from '@angular/core';
@Component({
selector: 'app-water-slider',
template: `<input type="range" min="0" max="100"
[value]="level()" (input)="onSlide($event)" />`,
})
export class WaterSlider {
level = model(0);
onSlide(e: Event) {
this.level.set(Number((e.target as HTMLInputElement).value));
}
}Unlike an input(), a model() is writable from inside the child, and each set sends the new value up.
On form fields, use ngModel from FormsModule:
@Component({
imports: [FormsModule],
template: `<input [(ngModel)]="nickname" />
<p>Hello, {{ nickname() }}</p>`,
})
export class EditPlant {
nickname = signal('');
}Notice [(ngModel)]="nickname", not nickname(). Two-way binding needs the signal itself so it can both read and write it.
The shortcut
When you see [(x)], mentally unfold it into [x] and (xChange). Every question about two-way binding becomes a question about one ordinary input and one ordinary output.
Unfold
[(ngModel)]="nickname"becomes[ngModel]="nickname()"plus(ngModelChange)="nickname.set($event)".
Drills
Answer fast — trust the rule.
Which is the correct two-way binding syntax?
[(size)]="potSize" expands to [size] plus which event?
How should a child declare a property that supports [(level)]?
nickname = signal(''). Which binding works?
Remember
[(x)]is shorthand for[x]in plus(xChange)out.- Use
model()for two-way props on your own components;ngModelplusFormsModulefor form fields. - Trap: calling the signal inside the banana box; pass
nickname, notnickname().
