Two-Way Binding [(ngModel)] and model()
Two-way binding synchronizes data between TypeScript and the template in both directions.
Two-way binding combines property binding [ ] and event binding ( ) into one syntax — [( )].
"Two-way = phone call — dono side se baat hoti hai."
- Property binding = One-way TV (TypeScript → Template only)
- Two-way binding = Phone call (TypeScript ↔ Template both directions)
When the user types in an input, the TypeScript property updates. When the TypeScript property changes (programmatically), the input updates. Both directions work automatically.
The old way uses [(ngModel)] — the famous "banana in a box" syntax:
<input [(ngModel)]="biryaniName">
It's called "banana in a box" because [( )] looks like a banana inside a box [ ].
Important: To use ngModel, you must import FormsModule:
import { FormsModule } from '@angular/forms';\n\n@Component({\n standalone: true,\n imports: [FormsModule], // ✅ Required for [(ngModel)]\n // ...\n})
Under the hood, [(ngModel)]="name" is syntactic sugar for: [ngModel]="name" (ngModelChange)="name = $event".
Angular 17+ introduced the model() signal — a cleaner way to create two-way binding without FormsModule:
// In component\nbiryaniName = model(''); // Creates a writable signal\n\n// In template\n<input [model]="biryaniName">
Benefits over ngModel:
- ✅ No FormsModule import needed
- ✅ Signal-based — better performance, change detection knows exact changes
- ✅ Cleaner syntax:
[model]instead of[(ngModel)] - ✅ Type-safe by default
"model() = naya smart phone — faster, cleaner, no extra settings."
Two-way binding works with custom components too:
Old way — @Input() + @Output() with EventEmitter:
// Child component\n@Input() biryaniName: string = '';\n@Output() biryaniNameChange = new EventEmitter<string>();\n\nupdateName(value: string) {\n this.biryaniName = value;\n this.biryaniNameChange.emit(value);\n}\n\n// Parent uses: [(biryaniName)]="name"
New way — model() signal in child:
// Child component\nbiryaniName = model(''); // ✅ One line, no boilerplate!\n\n// Parent uses: [model]="biryaniName"
"Custom component se bhi two-way — model() ne life easy kar di."
Here's when to use which approach:
- Simple form inputs → model() signal (new way, recommended)
- Template-driven forms → Still use [(ngModel)] with FormsModule. More feature-rich for forms.
- Reactive forms → Don't use either! Use FormControl with formControlName.
- Custom component two-way → model() in child (new way, highly recommended)
"Reactive forms ka apna system hai — agle stage mein padhenge." For now, remember that reactive forms are a completely different approach with FormGroup and FormControl.
Key Takeaways
- ✅ Two-way binding combines [ ] and ( ) into [( )] — data flows both directions.
- ✅ [(ngModel)] requires FormsModule import. Works but verbose.
- ✅ model() signal (Angular 17+) is the new way — no FormsModule needed, signal-based.
- ✅ Custom components can support two-way binding — old way: @Input+@Output, new way: model().
- ✅ Use model() for simple inputs, [(ngModel)] for template-driven forms, FormControl for reactive forms.
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login