Data binding

This is a short introduction to get you start and experience with Angular. For more information, please refer to Angular.io.

(Please tell me if you find any errors or omissions in the document, 3-April-2021)

Overview

  What is data binding?  

  • A feature to tie two JavaScript values together
    • When the first variable changes, the second is updated to reflect the changes to the first
  • Data binding is used to tie user interface (UI), so-called view, to a set of UI-independent values, referred to as model
    • Model consists of simple strings, numbers, and other primitive JavaScript types
    • View defines how to render the model
  • View and model can be tied directly from HTML using directives

Two classes of data binding

(based on how they interact with the JavaScript data in scopes)
  1. One-way binding
    • String interpolation — render data, not modify data, so-called "binding expression"
      • Bind model (component class) to view (DOM) using
        {{property-name-from-model}}
      • Should be used when dealing with string expression
      • Example: in view, binding-example.component.html
        <h1>{{ title }}</h1> 
        in component, binding-example.component.ts
        import { Component, OnInit } from '@angular/core';
        
        @Component({
          selector: 'app-binding-example',
          templateUrl: './binding-example.component.html',
          styleUrls: ['./binding-example.component.css']
        })
        export class BindingExampleComponent implements OnInit {
          constructor() { }
          title = 'Data binding example';
          ngOnInit() {
          }
        } 
        in view, app.component.html, include the following line
        <app-binding-example></app-binding-example>
      • Another example, in an order data model (order.ts class)
        export class Order {
           constructor(
              public name: string,
              public email: string,
              public phone: number,
              public drink: string,
              public tempPreference: string,
              public sendText: boolean,
           ){}
        }   
        in view, app.component.html, to access the email property of the data model,
        {{ orderModel.email }}
        to access the data model and display the data in JSON format,
        {{ orderModel | json }}
        (assuming an instance of the order data model, named orderModel, has been created in app.component.ts)

    • Property or attribute binding — render data, not modify data, set an attribute property of a view element
      • Bind model (component class) to view (DOM) using
        [HTML-attribute-name] = "property-name-from-model"
      • Should be used when dealing with non-string expression
      • Example: in view, binding-example.component.html
        <input type="text" name="content" [value]="msg" />
        in component, binding-example.component.ts
        import { Component, OnInit } from '@angular/core';
        
        @Component({
          selector: 'app-binding-example',
          templateUrl: './binding-example.component.html',
          styleUrls: ['./binding-example.component.css']
        })
        export class BindingExampleComponent implements OnInit {
          constructor() { }
          msg = 'Duh';
          ngOnInit() {
          }
        } 
        in view, app.component.html, include the following line
        <app-binding-example></app-binding-example>

    • Event binding — not render data, may modify data
      • Update or send the value information of a certain variable from view (DOM) to the model (component class) using
        (event-name) = "function-to-handle-the-event()"
      • Example: in view, binding-example.component.html
        <h1>{{ title }}</h1>
        <button (click)="changeTitle()">Change title on click of this button</button> 
        in component, binding-example.component.ts
        import { Component, OnInit } from '@angular/core';
        
        @Component({
          selector: 'app-binding-example',
          templateUrl: './binding-example.component.html',
          styleUrls: ['./binding-example.component.css']
        })
        export class BindingExampleComponent implements OnInit {
          constructor() { }
          title = 'Data binding example';
          ngOnInit() {
          }
          changeTitle() {
             this.title = 'Event binding';
          }
        } 
        in view, app.component.html, include the following line
        <app-binding-example></app-binding-example>

    • Class binding — not render data, not modify data, set a class property of a view element, using
      [class.css-class-selector]="optional-under-which-conditions-to-apply"
      • Example: in view, app.component.html
        <input type="text" required #name="ngModel"
           [class.is-invalid]="name.invalid && name.touched"
           class="form-control is-invalid" [(ngModel)]="orderModel.name" name="customer">
        <small class="text-danger" [class.d-none]="name.valid || name.untouched">Name is requried</small>  
        The above example assigns an ngModel to a template reference variable #name; therefore, allowing a template reference name to capture the value of this input box. The name reference variable is later used to determine if the css class should be applied to this form input (or view) element. The is-invalid css class selector is applied to this view element only if the element has invalid data entry (name.invalid) and has been visited (name.touched).

    • Style binding — not render data, not modify data, set a style of a view element, using
      [style.css-property]="value"
      • Example: in view, app.component.html
        <p [style.color]="'red'">set element property, using attribute directive</p>

  2. Two-way binding
    • Combine property and event binding, using ngModel directive
      [(ngModel)] = "property-name-from-model
    • Changes made in the component's data synch to the view; changes made in the view immediately update the model (the component's data)
    • Mainly used in data entry forms
    • Example: in view, binding-example.component.html
      <input type="text" name="content" [(ngModel)]="msg" />
      in component, binding-example.component.ts
      import { Component, OnInit } from '@angular/core';
      
      @Component({
        selector: 'app-binding-example',
        templateUrl: './binding-example.component.html',
        styleUrls: ['./binding-example.component.css']
      })
      export class BindingExampleComponent implements OnInit {
        constructor() { }
        msg = 'Duh';
        ngOnInit() {
        }
      } 
      in view, app.component.html, include the following line
      <app-binding-example></app-binding-example>
    • Another example, in an order data model (order.ts class)
      export class Order {
         constructor(
            public name: string,
            public email: string,
            public phone: number,
            public drink: string,
            public tempPreference: string,
            public sendText: boolean,
         ){}
      }   
      in view, app.component.html, to access the email property of the data model,
      <input [(ngModel)]="orderModel.email"
         type="email" class="form-control" name="email">  
      (assuming an instance of the order data model, named orderModel, has been created in app.component.ts)

What can data binding do?

Three primary advantages

  • Model and controller logic are completely independent of UI
    • The controller code can load data and provide API to the HTML for data manipulation and hanlder loading and saving the data, while all decisions for how data are presented can be in HTML and CSS.
    • When working in a team, UI designer(s) can focus on how the data are presented to users while developer(s) can focus on getting the data (model) from the server to the browser. With data binding:
      • UI designers do not have to code JavaScript
      • Developers do not have to tweak HTML/CSS
      • The JavaScript and HTML/CSS interact through API, with the developers writing JavaScript functions and exposing variables in the controller, and the designers tying into these using directives from their HTML
  • Code can be written in declarative language, less code in imperative language
    • Declarative programming
      • Specify what should happen, while allowing a computer to optimize the details of how it should be done
      • Example: Rather than writing code to explicitly construct UI objects, you simply define how you want the objects to be structured and let the browser handle the rendering specific
      • Lead to short and clean code
    • Imperative programming
      • Provide the computer with exact instructions for how to execute a task
  • A controller can be reused in different places without making changes to the JavaScript.