Two-Way Binding with ngModel
Property binding ([property]) flows data into the DOM. Event binding ((event)) flows events out of the DOM. Two-way binding does both at once — it keeps a class property and a form input in sync. Angular provides this through [(ngModel)].
The banana-in-a-box syntax
Section titled “The banana-in-a-box syntax”[(ngModel)] is shorthand for combining [ngModel] (property binding) and (ngModelChange) (event binding). The nickname “banana in a box” comes from the visual: [()].
<input [(ngModel)]="searchQuery" placeholder="Search movies..." /><p>You typed: {{ searchQuery }}</p>searchQuery = '';As the user types, searchQuery is updated in real time. The displayed paragraph updates to match. Change searchQuery in the class (via a method or timer), and the input reflects the new value.
Importing FormsModule
Section titled “Importing FormsModule”NgModel comes from @angular/forms. To use it, add FormsModule to the component’s imports array:
import { Component } from '@angular/core';import { FormsModule } from '@angular/forms';
@Component({ selector: 'app-search', standalone: true, imports: [FormsModule], template: ` <input [(ngModel)]="query" placeholder="Search..." /> <p>{{ query }}</p> `})export class Search { query = '';}Without FormsModule, Angular will not recognize [(ngModel)] and the template will not compile.
Two-way binding vs. reactive forms
Section titled “Two-way binding vs. reactive forms”[(ngModel)] is part of Angular’s template-driven forms approach. It is simple and works well for basic inputs — a single search field, a toggle, a text input.
For more complex scenarios — multiple fields, validation, dynamic forms, debounced API calls — Angular’s reactive forms (covered in Module 06) are better. They give you a TypeScript object that represents the entire form, which is easier to validate and test.
In CinemaVault:
- The NavBar search input uses
[(ngModel)]— it is a single field that reads a query and navigates. - The Browse filter form uses reactive forms — it has multiple fields (genre, year, sort) that need to be watched together.
Under the hood
Section titled “Under the hood”[(ngModel)]="prop" is exactly equivalent to:
<input [ngModel]="prop" (ngModelChange)="prop = $event" />The [ngModel] sets the input’s value from prop. The (ngModelChange) event fires when the user changes the input and updates prop with the new value. The [()] syntax is syntactic sugar that writes this for you.
Exercise
Section titled “Exercise”- Create a
components/search-barcomponent withFormsModulein imports. - Add a
query = ''property. - Add
<input [(ngModel)]="query" placeholder="Search..." />to the template. - Display the current
querybelow the input with<p>Searching for: {{ query }}</p>. - Add a “Clear” button with
(click)="query = ''"and confirm that clicking it clears both the input and the displayed text simultaneously.
[(ngModel)]is two-way binding — it keeps a class property and an input value in sync automatically.- It is shorthand for
[ngModel]="prop" (ngModelChange)="prop = $event". - Add
FormsModuleto the component’simportsarray to useNgModel. - Use
[(ngModel)]for simple single-field inputs; use reactive forms (Module 06) for complex forms with validation and multiple fields.