[Tutorial] Create your own two-way data binding in Angular

You’re probably familiar with [(ngModel)] and its world-famous “banana in a box” syntax. In this post, I’m going to explain how ngModel actually works, which will allow us to replicate its behavior in order to implement our own two-way data binding.

In the end, we‘re going to create a component that takes a message as a parameter, and that message will be our component model. We would use that component as follows:

<example-component [(message)]="title"></example-component>

Highlighted in the above code is the two-way data binding we’re looking to implement.

First, let’s dissect the “banana in the box” syntax applied to ngModel. Here is the syntax that we all know about:

<input [(ngModel)]="title" type="text">

What’s interesting is that the [()] turns out to be syntactic sugar for the following:

<input [ngModel]="title" (ngModelChange)="title= $event" type="text">

The above code is definitely more verbose but it makes perfect sense when you think about it. A two-way data-binding is really… two one-way data-bindings, right?

Now the real secret that the above example unveils is the use of the Change suffix.

Let’s apply this trick to our own example component.

First let’s create a simple component with a @Input to have a one-way data binding:

export class TwoWayDataBindingExampleComponent  {

messageValue : string;

@Input()
get message(){
return this.messageValue;
}
set message(val) {
this.messageValue = val;
}
}


There are two important things to note here. First I use a property messageValue to store the actual message. Then I expose it as message, so that I can use TypeScript getters and setters to read and set the value of messageValue.

This is a key part of the technique since our setter will have to do some more work to actually notify other components of any model update.

Here is how we implement the second one-way data-binding:

export class TwoWayDataBindingExampleComponent  {

messageValue : string;

@Output()
messageChange = new EventEmitter();

@Input()
get message(){
return this.messageValue;
}

set message(val) {
this.messageValue = val;
this.messageChange.emit(this.messageValue);
}
}


Now we have everything in place. Both the getter and setter use messageValue to read / update our data model, but the setter also notifies the rest of the world by emitting an event.

As a result, we can now have a two-way data binding applied to that component with the following syntax:

<example-component [(message)]="title"></example-component>

Wasn’t that easy? Well, it sure is once we know the trick to get there. Now you can implement two-way data-bindings in your own components!

What’s the difference between [style] and [ngStyle] in Angular?

When you need to apply dynamic styles to a HTML element using Angular, there are different options to consider.

The first and most obvious solution is to use the regular style or class HTML attributes along with Angular data-bindings, which looks like this:


<div [style.color]="errorMessageColor">
The phone number you entered does not match the expected format
</div>

The above code would style the div using a color value set on the errorMessageColor property of your component. Thanks to the data binding, whenever that property changes, the div would get a new color.

You can make the above example even more powerful using the ternary operator in your expression to express a conditional styling:


<div [style.color]="hasError ? 'red' : 'black' ">
The phone number you entered does not match the expected format
</div>

The above example assumes that hasError can evaluate to true, which is convenient since in Javascript anything that is not null nor undefined would work. As a result, if hasError is something that isn’t null nor undefined nor false, then the message will show up in red color, otherwise it will be black.

This is great but it can get quite verbose if you want to apply multiple styles to the same element:


<div [style.color]="hasError ? 'red' : 'black' " [style.font]="font" [style.background-color]="hasError ? 'tomato' : 'white' ">
The phone number you entered does not match the expected format
</div>

In that case, using a CSS class is a much better option as you can refactor those CSS properties in one place and possibly reuse them on other HTML elements.

Sometimes, you might need very specific CSS properties based on different conditions though. That’s where ngStyle comes into play. With ngStyle, you can bind to an object that expresses as many conditions and cases as you need:


<div [ngStyle]="currentStyles">
The phone number you entered does not match the expected format
</div>

And then in your component code:

this.currentStyles = {
'font-style': this.canSave ? 'italic' : 'normal',
'color': this.hasError ? 'red' : 'black',
'font-size': this.hasError ? '24px' : '12px'
};

Now you can express as many different styles as needed. ngStyle is an Angular directive that gives you the flexibility to do this, where as style is a regular HTML property to which you can only bind values one by one. That’s the difference between the two of them.

Note that the same distinction of behavior applies between class and ngClass, where the former is meant to be used for single bindings, and the latter can be used to bind to a decision object similar to the one showed above for ngStyle.