Chapter 3.4☕ 16 min read

Two-Way Binding [(ngModel)] and model()

Two-way binding synchronizes data between TypeScript and the template in both directions.

01What is Two-Way Binding

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.

02Old Way — [(ngModel)]

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".

03New Way — model() Signal (Angular 17+)

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."

04Two-Way with Custom Components

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."

05When to Use What

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.
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase