Angular2: Data Binding


In the previous article, we had explored how dependency injection works in Angular2 compared to Angular1. In this article, I will walk you through the one-way vs two way data binding and how its different but quite similar in Angular2.

Angular1

As usual, we’ll quickly go through the Angular1 example. Let’s take a simple example (HTML) from my free ebook on Angular1 Directives that explores how data binding works in Angular1. Notice we have not written a single line of Javascript code to enable the data binding in the following example:

<html ng-app="App">
<head>
  <title>Two way Data Binding with Form Controls</title>
  <script src="../bower_components/angular/angular.js"></script>
</head>
<body>
  <input type='checkbox' ng-model='choose' />
  <div>{{choose}}</div>

  <button ng-click="choose=!choose">Toggle Checkbox</button>

  <script type="text/javascript">
    angular.module('App', []);
  </script>
</body>
</html>

Now that we’ve a working demo, let us migrate it to Angular2.

Angular2

Let us create a typescript file twoway-binding.ts first to lay our main component.

import { NgModule, Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

@Component({
  selector: 'ng-app',
  template: `
    <input type='checkbox' [(ngModel)]='choose' />
    <div>{{choose}}</div>
    <button (click)="choose=!choose">Toggle Checkbox</button>
  `
})
export class DataBindingComponent {
  choose: boolean = true;
}

@NgModule({
  declarations: [DataBindingComponent],
  imports:      [BrowserModule, FormsModule],
  bootstrap:    [DataBindingComponent]
})
export default class MyAppModule {}

platformBrowserDynamic().bootstrapModule(MyAppModule);

We are already familiar with Component, ES6 Class, bootstrap, etc. jargons from the first article as those are the backbone of Angular2. The only difference here is the template with data-binding expressions.

In Angular1, the two-way data binding was enabled by default, for one-way data binding the expression should be wrapped in {{choose}}. Also the attribute name supposed to be hyphenated. However, in Angular2 the attribute should be in camel-case with subtle differences that affect the way data flows:

  1. [Component -> Template]
    To show a model in a template which was defined in the component, use square-bracket or double-curly syntax a.k.a. One Way Binding.
  2. (Template -> Component)
    To broadcast an event from a template in order to update the model in the component, use round-bracket syntax a.k.a. One Way Binding.
  3. [(Component -> Template -> Component)]
    To have both behaviors simultaneously, use round-bracket inside square-bracket (or banana-in-the-box) syntax a.k.a. Two Way Binding.

This clearly means that the two-way binding in Angular2 is opt-in and can be enabled by importing BrowserModule to plug it in the NgModule.

In the above example, we want to toggle the expression choose from the template to the component using (click) when the button is clicked and update the checkbox in the template immediately using [ngModel]="choose". We also want to update the model choose in the component if the checkbox is toggled manually using [(ngModel)]="choose". Do not get confused with one-time binding in Angular1 i.e. {{::choose}} where the model used to be freezed once evaluated, there is no such thing in Angular2.

Now let us update HTML markup as usual.

<html>
<head>
  <title>Angular2: Two way Data Binding with Form Controls</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <!-- 1. Load libraries -->
  <script src="../node_modules/core-js/client/shim.min.js"></script>
  <script src="../node_modules/zone.js/dist/zone.js"></script>
  <script src="../node_modules/reflect-metadata/Reflect.js"></script>
  <script src="../node_modules/systemjs/dist/system.src.js"></script>

  <!-- 2. Configure SystemJS -->
  <script src="../systemjs.config.js"></script>
  <script>
    System.import('ch01/twoway-binding').catch(function(err){ console.error(err); });
  </script>
</head>
<body>
  <!-- 3. Display the application -->
  <ng-app>Loading...</ng-app>
</body>
</html>

Wrap up

Remember, because of the simplified template syntax in Angular2, you can do lot of things easily such as,

  • {{textContent}} becomes [textContent]="textContent"
  • ng-bind-html="html" becomes [innerHTML]="html"
  • ng-mouseup="onMouseUp()" becomes (mouseup)="mouseUp()"
  • my-custom-event="fire()" becomes (customEvent)="fire()"

Fewer templating syntax means Faster learning! Head over to a live data binding in action.