← Back to all tutorials

2 Way Data Binding

Master two-way data binding with ngModel — keep the component and template in sync automatically.

2 Way Data Binding

Two-way data binding keeps the component property and the template input in sync. When the user types, the property updates. When the property changes in code, the input updates.

Setting Up ngModel

First, import FormsModule in your module:

// app.module.ts
import { FormsModule } from '@angular/forms';

@NgModule({
    imports: [
        BrowserModule,
        FormsModule  // ← Required for ngModel!
    ],
    // ...
})

Basic Two-Way Binding

// component
export class FormComponent {
    username = '';
}

// template
<input [(ngModel)]="username" placeholder="Enter username">
<p>Hello, {{ username }}!</p>

As you type in the input, the paragraph updates instantly. The [(ngModel)] syntax is sometimes called "banana in a box" — [()].

How It Works Under the Hood

<!-- [(ngModel)] is shorthand for: -->
<input 
    [ngModel]="username"           
    (ngModelChange)="username = $event"  
>

<!-- Which is essentially: -->
<input 
    [value]="username"              <!-- Property binding: component → input -->
    (input)="username = $event.target.value"  <!-- Event binding: input → component -->
>

Form Example

// component
export class ContactFormComponent {
    name = '';
    email = '';
    message = '';
    subscribe = false;
    priority = 'normal';

    onSubmit(): void {
        console.log({
            name: this.name,
            email: this.email,
            message: this.message,
            subscribe: this.subscribe,
            priority: this.priority,
        });
    }
}

// template
<form (submit)="onSubmit()">
    <div class="field">
        <label>Name</label>
        <input [(ngModel)]="name" name="name" type="text">
    </div>

    <div class="field">
        <label>Email</label>
        <input [(ngModel)]="email" name="email" type="email">
    </div>

    <div class="field">
        <label>Message</label>
        <textarea [(ngModel)]="message" name="message"></textarea>
    </div>

    <div class="field">
        <label>
            <input [(ngModel)]="subscribe" name="subscribe" type="checkbox">
            Subscribe to newsletter
        </label>
    </div>

    <div class="field">
        <label>Priority</label>
        <select [(ngModel)]="priority" name="priority">
            <option value="low">Low</option>
            <option value="normal">Normal</option>
            <option value="high">High</option>
        </select>
    </div>

    <button type="submit">Send</button>
</form>

<!-- Live preview -->
<div class="preview">
    <p><strong>Name:</strong> {{ name }}</p>
    <p><strong>Email:</strong> {{ email }}</p>
    <p><strong>Priority:</strong> {{ priority }}</p>
    <p><strong>Subscribe:</strong> {{ subscribe }}</p>
</div>

Important: name Attribute Required

When using ngModel inside a <form>, each input must have a name attribute:

<!-- ❌ Error without name: -->
<input [(ngModel)]="email">

<!-- ✅ Works with name: -->
<input [(ngModel)]="email" name="email">

Key Takeaways

  • [(ngModel)] creates two-way binding — input and property stay in sync
  • Requires FormsModule to be imported in your module
  • [(ngModel)] = [ngModel] (property) + (ngModelChange) (event)
  • Works with <input>, <textarea>, <select>, and checkboxes
  • Inside a <form>, every ngModel input needs a name attribute