Ad

Angular the series Part 6: Data Binding

    

    In this section, we're going to look at how to display data and handle events. Data binding is kind of communication between your typescript code of your component, your business logic and the template. You might have some result from typescript code like data fetching from server, or result from some calculations that you want to display to the user. So we need some kind of communication between both pieces to be able to do something in our app.

    There are some different ways of data binding. If we want to output data from our typescript code in the HTML template, we can use string interpolation or property binding. In the other direction, if we want to trigger something in your typescript code when users interact with the UI, you can use event binding. And we also have one additional form of data binding where we combine both directions, two-way binding, where we are able to react events and output something at the same time.

1. String interpolation

String interpolation is a one-way data binding technique, it can only transfer the data from typescript code to an HTML template. By default, interpolation uses the double curly braces {{ and }} as delimiters. Inside the braces, you can write a typescript expression. So, the easiest expression is to simply reference a property:

my-new-component.component.html<p>{{greeting}}</p>
my-new-component.component.tsimport { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-my-new-component',
  templateUrl: './my-new-component.component.html',
  styleUrls: ['./my-new-component.component.scss']
})
export class MyNewComponentComponent implements OnInit {
  greeting: string = "Hello from Tian";
  isError: boolean = true;

  constructor() { }

  ngOnInit(): void {
  }
}

   You could also hard code a string in there, or any expression which can be resolved to a string in the end, and that's the only condition for a string interpolation syntax. Whatever you have between the curly braces, it has to return a string, you can call a method which returns a string. The only restriction is that you cannot write multi-line expression, for example you cannot write a block expression or add an if or for control structure, but you still can use ternary expression.

my-new-component.component.html<p>{{"Another Hello"}}</p>
<p>{{1+1}}</p>
<p>{{isError ? "true" : "false"}}</p>


2. Property binding

    Property binding is another type of one-way binding allows you to set values for properties of HTML elements or directives (which I will introduce to you later in this series). With property binding, we can do things such as dynamically disable a button, programmatically set path for a tag, or share values between components.

    To use property binding, enclose the property with square brackets []. and pass an expression between the quotation marks. The expression can be the HTML attributes or any properties you declare on your on. The brackets [ ] cause Angular to treat the assignment as a dynamic expression, without the brackets, Angular just considers it as a normal string.

my-new-component.component.html<button [disabled]="!isError"></button>

In most cases, we can replace string interpolation with property binding and vice versa.

my-new-component.component.html<p>{{greeting}}</p>
<p [innerHTML]="greeting"></p>

<img src="{{imagePath}}">
<img [src]="imagePath">

However, if you want to set an element property to a non-string data value, you must use property binding.


3. Event binding

    Let's imagine we have a button, and when the button is clicked, we want to do something in our business logic, like saving the data, or recalculate the statics. So, we have to apply the event binding for that button. Event binding allows us to interact with user actions to our UI keypress, clicks, mouse movements, touches...

To use event binding, you must put a target event name within parentheses on the left of an equal sign, and a statement between quotation marks on the right.

my-new-component.component.html<button (click)="saveData()">Save</button>
my-new-component.component.tsimport { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-my-new-component',
  templateUrl: './my-new-component.component.html',
  styleUrls: ['./my-new-component.component.scss']
})
export class MyNewComponentComponent implements OnInit {
  constructor() { }

  ngOnInit(): void {
  }

  saveData() {
      console.log("This is the saveData() method");
  }
}

On the above example, the event binding will listen for the button's click event and execute saveData() method on your typescript code when user clicks to that button. You can also pass multiple statements just like this:

my-new-component.component.html<button (click)="saveData(); calculateStatics(); isDisabled = true">Save</button>


4. Two-way binding

    Two-way binding is a combination of property binding and event binding. Property binding is used to set the element property while event binding will listen to the element change events. Two-way binding syntax is [()], which is the combination of the square brackets [] or property binding with the parenthesis () of event binding. A trick to remember this syntax is Banana () in the box []

You can create your custom two-way binding, but in most case we will use the Angular predefined [(ngModel)] directive.

my-new-component.component.html<input [(ngModel)]="username">
my-new-component.component.tsimport { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-my-new-component',
  templateUrl: './my-new-component.component.html',
  styleUrls: ['./my-new-component.component.scss']
})
export class MyNewComponentComponent implements OnInit {
  username: string = "tian";

  constructor() { }

  ngOnInit(): void {
  }
}

As soon as the component is initialized, the value of username will be bound to the input control. And whenever the users change the value of the input, it will also immediately update the username variable.

Because ngModel directive belongs to FormModule, you must import this module inside the module your component is declared.

app.module.tsimport { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { MyNewComponentComponent } from './my-new-component/my-new-component.component';
import { FormsModule } from '@angular/forms';
    
@NgModule({
  declarations: [
      AppComponent,
      MyNewComponentComponent,
  ],
  imports: [
      BrowserModule,
      FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }