Angular 2 still has two-way data binding, but the way it behaves is a bit different than what you're used to. This recipe will begin with a very simple example and then break it down into pieces to describe what it's actually doing.
The code, links, and a live example related to this recipe are available at .
Two-way data binding uses the ngModel
directive, which is included in FormsModule
. Add this directive to your application module:
[app/app.module.ts] import {NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {FormsModule} from '@angular/forms'; import {ArticleEditorComponent} from './article-editor.component'; @NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ ArticleEditorComponent ], bootstrap: [ ArticleEditorComponent ] }) export class AppModule {}
Next, flesh out your component, which will have two instances of input bound to the same component member using ngModel
:
[app/article-editor.component.ts] import {Component} from '@angular/core'; @Component({ selector: 'article-editor', template: ` <input [(ngModel)]="title"> <input [(ngModel)]="title"> <h2>{{title}}</h2> ` }) export class ArticleEditorComponent { title:string; }
That's all that's required! You should see input modifications instantly reflected in the other input as well as in <h2>
itself.
What you're really doing is binding to the event and property that ngModel
associates with this input. When the component's title
member changes, the input is bound to that value and will update its own value. When the input's value changes, it emits an event, which ngModel
will bind to and extract the value from before propagating it to the component's title
member.
The banana-in-a-box syntax [()]
is simply indicative of the binding done to both the input property with []
and the input events with ()
.
In reality, this is shorthand for the following:
[app/article-editor.component.ts] import {Component} from '@angular/core'; @Component({ selector: 'article-editor', template: ` <input [ngModel]="title" (ngModelChange)="title=$event"> <input [ngModel]="title" (ngModelChange)="title=$event"> <h2>{{title}}</h2> ` }) export class ArticleEditorComponent { title:string; }
You will find that this behaves identically to what we discussed before.
You might still find that there's a bit too much syntactical sugar happening here for your taste. You're binding to ngModel
, but somehow, it is equivalent to the input value. Similarly, you're binding to ngModelChange
events, which are all emitting a $event that appears to be only a string.
This is indeed correct. The ngModel
directive understands what it is a part of and is able to integrate [ngModel]
and (ngModelChange)
correctly to associate the desired bindings.
The core of these bindings is essentially doing the following:
[app/article-editor.component.ts] import {Component} from '@angular/core'; @Component({ selector: 'article-editor', template: ` <input [value]="title" (input)="title=$event.target.value"> <input [value]="title" (input)="title=$event.target.value"> <h2>{{title}}</h2> ` }) export class ArticleEditorComponent { // Initialize title, otherwise you'll get "undefined" title:string = ''; }