Two-way Data Binding in Angular 2

By default Angular 2 doesn’t use a two-way data binding. It uses a unidirectional binding but if offers you a simple syntax for a two-way data binding if need be. In this blog I’ll show you an example of such syntax.

One-way binding from the UI an Angular component is arranged by surrounding an event name with parentheses:

<button (click)="onClick()">Get Products</button>

<input placeholder= "Product name" (input)="onInput()">

The one-way binding in the opposite direction is denoted by surrounding an HTML attribute with square brackets. The greeting is a property of an Angular component in this line:

<input [value]="greeting" >

There is also a template binding that allows to add/remove HTML elements to the DOM tree. The following line will add the only if a boolean flag is true, for example:

<span *ngIf="flag">Flag is true</span>

In limited cases you may want to use two-way binding, and you can specify it by adding the ngModel directive as an HTML attribute surrounded with both parentheses and square brackets, for example:

<input [(ngModel)] = "myComponentProperty">

In other frameworks two-way binding is popular with forms where you often needed to synchronize values of the form fields with the underlying model. While Angular also allows you to map each form field to the corresponding property of the model object there is a better way to handle forms and I’ll write about it in a separate blog. Still, there are some cases when using ngModel may be handy, so let’s get familiar with the syntax.

Say the landing page of a financial application allows the user to check the latest prices of the stock by entering its symbol in an input field. Often the user enters the same stock that he owns or follows, e.g. AAPL for Apple. You could save the last entered symbol as a cookie or using the HTML5 local storage, and next time the user opens this page the program reads it from there and populates the input field. The user still should be able to type in this field and the entered value should be synchronized with a variable lastStockSymbol, which plays the role of the model (as in MVC). The code sample below implements this functionality.

import {bootstrap} from 'angular2/platform/browser';
import {Component} from 'angular2/core';

@Component({
    selector: 'stock-search',
    template: `<input type='text' 
        placeholder= "Enter stock symbol" [(ngModel)] = "lastStockSymbol"> // 1
               <br>The value of lastStockSymbol is {{lastStockSymbol}}`
})
class StockComponent {

    lastStockSymbol: string; // 2

    constructor() {
        setTimeout(() => { // 3            
            this.lastStockSymbol="AAPL"; 
        }, 1000);
    }
}
@Component({
    selector: 'app',
    directives: [StockComponent],
    template:`<stock-search></stock-search>`

})
class AppComponent {}
bootstrap(AppComponent);

1. Requesting the two-way binding to synchronize the changes in the input field with lastStockSymbol

2. The lastStockSymbol is our model and it can be modified either by user typing in the input field or programatically.

3. To emulate a scenario of reading the last stock symbol we simply arranged a one second delay after which the value of the variable lastStockSymbol will be changed to AAPL and the <input>> field will show it.

The variable lastStockSymbol and the value of the <input> field will be always in sync, and you can see this in action by trying it online on Plunker at http://bit.ly/1MDExS2. A little bit fancier version of this sample is located at http://plnkr.co/edit/bOOkz96iIjFu9ydHKNNy

In AngularJS 1.x the two-way binding was a default mode of operations, which seems like a simple and elegant solution for synchronization of a view and a model. But on a complex UI containing dozens of controls, where changing the value in one place could cause a chain of bindings updates performance could suffer.

Debugging could also be more difficult as there could be many reasons of why a particular value was changed. Was it because of the user’s input or it’s a result of modified value in seemingly unrelated variable in the program? With two-way binding implementing the change detection inside the framework was not trivial either. With the unidirectional data flow you always know where a change to a particular UI element or a component property came from. We’ll discuss Angular’s change detection mechanism in on of the future blogs.

My other Angular-related blogs are here. Manning is publishing the drafts of the book “Angular 2 Development with TypeScript“ that I write with Anton Moiseev. Starting on February 28, we’ll also teach an online class on Angular 2.

8 thoughts on “Two-way Data Binding in Angular 2

  1. Thank you!

    I had not payed attention to the return value of setInterval() and was wondering what parameter to give to clearInterval().

    It works now, like this:

    myCounterId: int;
    start(){
    myCounterId = setInterval(() => {
    this.timer.time–;
    }, 1000);
    }
    reset(){
    clearInterval(myCounterId);
    this.timer.time = 1500; //time in seconds
    }

  2. May I ask another question?
    How can I display, instead of {{lastStockSymbol}}, the result of a function call taking {{lastStockSymbol}} as an argument?
    For example, in my program, I have {{timer.time}}, in seconds, and I would like to display convert ({{timer.time}}), where convert() is:
    convert(length){
    var minutes = parseInt( length / 60 ) % 60;
    var seconds = length % 60;
    return (minutes + “:” + seconds);
    }

Leave a comment