Data binding can be confusing when you’re getting started in Angular. Let’s break it down! This post covers two-way data binding.
In the past several posts, we have taken an expansive look at data binding in one direction, either from the template to component or from component to template. Today we will be looking at two-way data binding in Angular.
This post is suited for all levels of frontend developers who use Angular, so being conversant with beginner concepts and installation processes is not assumed. Here are a few prerequisites you should have before you start to use Angular 12 and follow along through this article’s demonstration:
// run the command in a terminal
ng version
Confirm that you are using version 12, and update to 12 if you are not.
Other nice-to-haves include:
When you bind events in your Angular template to a component, and where the changes made in the template are also updated in the component data, what you are doing is called two-way data binding. The data flow here is bi-directional, meaning it can go both ways. A good description of it is that it is a combination of both event binding and property binding.
One of the most popular use cases for two-way data binding is working with forms. Many times, you would like to represent data you collect from a user in real-time in one way or another.
In two-way data binding, data is bound using the ngModel directive, which requires the Angular FormsModule to work. The banana-in-a-box syntax for this looks something like this:
<input [(ngModel)]="component property">
We are going to use the Angular CLI to generate a new test application where we can test out two-way data binding and show how you can easily use it in your workflow today.
More specifically, we are going to replicate this typing game with a function that allows you see exactly what you type in an input box in another element in the template.
Open your VS Code in the location of your choice, open the terminal and run this command:
ng new twoway
Make sure to answer the prompts like this:
? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? CSS
Now that your new project has been generated, navigate into it like this:
cd twoway
ng serve
Now navigate to the src folder and inside the app component.html file, copy the styles there into the app.component.css file. Then replace the content of the application with the code block below:
<div class="toolbar" role="banner">
<span>Welcome</span>
<div class="spacer"></div>
<a aria-label="Angular on twitter" target="_blank" rel="noopener" href="https://twitter.com/angular" title="Twitter">
</a>
</div>
<div class="content" role="main">
<!-- Highlight Card -->
<div class="card highlight-card card-small">
<svg id="rocket" alt="Rocket Ship" xmlns="http://www.w3.org/2000/svg" width="101.678" height="101.678" viewBox="0 0 101.678 101.678">
<g id="Group_83" data-name="Group 83" transform="translate(-141 -696)">
<circle id="Ellipse_8" data-name="Ellipse 8" cx="50.839" cy="50.839" r="50.839" transform="translate(141 696)" fill="#dd0031"/>
</g>
</svg>
<span>{{ title }} app is running!</span>
<svg id="rocket-smoke" alt="Rocket Ship Smoke" xmlns="http://www.w3.org/2000/svg" width="516.119" height="1083.632" viewBox="0 0 516.119 1083.632">
</svg>
</div>
<!-- Resources -->
<h2>Resources</h2>
<p>Here are some links to help you get started:</p>
<div class="card-container">
<a class="card" target="_blank" rel="noopener" href=#>
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"></svg>
<span>Hello</span>
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"></svg> </a>
<a class="card" target="_blank" rel="noopener" href=#>
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"></svg>
<span>Hello</span>
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"></svg>
</a>
<a class="card" target="_blank" rel="noopener" href=#>
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"></svg>
<span>Hello</span>
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"></svg>
</a>
</div>
</div>
If you run the command below in your terminal, the app should now look like this:
ng serve
Just as we discussed earlier, two-way binding is the combination of property binding and event binding, so we will try to achieve that now with the example above.
Open the app component HTML file and in the highlight card section, replace the content with the code block below:
<h2>Type anything</h2>
<input type="text" [value]="name" (input)="name=$event.target.value">
<hr>
<div class="spacer"></div>
<a aria-label="Angular on twitter" target="_blank" rel="noopener" href="https://twitter.com/angular" title="Twitter">
</a>
</div>
<div class="content" role="main">
<!-- Highlight Card -->
<div class="card highlight-card card-small">
<svg id="rocket" alt="Rocket Ship" xmlns="http://www.w3.org/2000/svg" width="101.678" height="101.678" viewBox="0 0 101.678 101.678">
<g id="Group_83" data-name="Group 83" transform="translate(-141 -696)">
<circle id="Ellipse_8" data-name="Ellipse 8" cx="50.839" cy="50.839" r="50.839" transform="translate(141 696)" fill="#dd0031"/>
</g>
</svg>
<span>You just typed {{name}}</span>
<svg id="rocket-smoke" alt="Rocket Ship Smoke" xmlns="http://www.w3.org/2000/svg" width="516.119" height="1083.632" viewBox="0 0 516.119 1083.632">
</svg>
</div>
Now you can see the property binding we created, assigning the input from the user to the name property, and then binding the event target on the same element to the same property. This is literally how event binding works.
Defining the name property, open the app component.ts file and replace the content with this code block:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'twoway';
name="";
}
If you save all the files now and check your browser at localhost:4200 it should be exactly as you expect.
Angular has a directive that makes this process even easier to manage in one straight statement. The directive is called the ngModel directive used in Angular to handle data binding. The best use case where ngModel is useful is when handling forms in your applications.
Change these lines in the app component.html file from:
<input type="text" [value]="name" (input)="name=$event.target.value">
<span>You just typed {{name}}</span>
to this code block below:
<input type="text" name="value" [(ngModel)]="value">
<span>You just typed {{value}}</span>
For this to work, we have to import the FormsModule in our app module file:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent
],
imports: [
FormsModule,
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Finally, change the property name in the component.ts file from name to value and you are all set.
We have just looked at two-way data binding in Angular, the original way to achieve it and how Angular made it even easier through ngModel. We saw how useful it can be to be able to bind data in two directions instead of just one as we have seen in the recent posts. How would you like to use ngModel in your forms today?
Nwose Lotanna Victor is a web technology enthusiast who documents his learning process with technical articles and tutorials. He is a freelance frontend web developer based in Lagos, Nigeria. Passionate about inclusion, community-building and movies in Africa, he enjoys learning new things and traveling.