[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.

The new HttpClient in Angular 4

Angular 4.3 was released with the addition of a new service to make HTTP requests: HttpClient.

The old Http service is still available and the main goal of HttpClient is to provide a simpler API out of the box.

Let’s see how the two compare for a simple HTTP GET request. First the new HttpClient:


constructor(private http: HttpClient) {
this.http.get("http://localhost:8080/personList")
.subscribe(res => this.persons = res );

And here is the same request made with the Http service:


constructor(private http: Http) {
this.http.get("http://localhost:8080/personList")
.map(res => res.json())
.subscribe(res => this.persons = res );
}

The only difference is that we don’t have to map the response to get our JSON data. HttpClient was written for JSON and as a result extracts our data for us.

Basically, Http.get() returns an Observable, where the Response is an HTTP response with HTTP headers, status code, and our data.

HttpClient.get() directly returns an Observable<Object> by default. It is just our data without the HTTP protocol information.

This is where HttpClient gets more interesting, as we can also define the type of the object we expect from the server using generics:


persons : Person[];

constructor(private http: HttpClient) {
// Now we expect the data to be an array of Person objects
this.http.get<Person[]>("http://localhost:8080/personList")
.subscribe(res => this.persons = res );
}

We can achieve the same strong typing with Http in a much more verbose way, which definitely highlights the benefits of using the new HttpClient:


persons : Person[];

constructor(private http: Http) {
let obs : Observable<Response> = http.get("....");
let obs2 : Observable<Person[]> = obs.map(res => res.json());
obs2.subscribe(res => this.persons = res);
}

What if I want to see the HTTP response?

Not a problem, just ask for it:


constructor(private http: HttpClient) {
this.http.get<Person[]>("....", {observe: 'response'}))
// Now res is of type HttpResponse.
// We can access our data through the body property.
.subscribe(res => this.persons = res.data );
}

What if I want to know when a HTTP error happens?

Just like with Http, you can register a handler for that. The error passed to the handler function will be of type HttpErrorResponse and has all of the information one would expect to find there:


constructor(private http: HttpClient) {
this.http.get<Person[]>("http://localhost:8080/personList"))
.subscribe(res => this.persons = res.data,
error => console.log(`Server error: ${err.status} - Details: ${err.error}`)
);
}

Now you know about the main differences between Http and HttpClient from a usage standpoint.

But HttpClient has a lot more to offer:

  • We can register interceptors for HTTP requests and responses (à la Angular JS)
  • There is also a HttpClientTestingModule to easily mock our HTTP requests for testing purposes

Interceptors are a major feature and I will talk about them in more details with a specific tutorial in the near future.

Some use cases of interceptors include, and are not limited to:

  • Adding HTTP headers on the fly for every single HTTP request (think authentication token for instance)
  • Implementing your own caching mechanism
  • Watching the progress of your request to display an accurate progress bar

The new HttpClient comes with Angular 4.3 in a new module: HttpClientModule, which is found in the @angular/common/http package.

Don’t hesitate to give it a try!

TypeScript Object Rest

In my last post,  I focused on TypeScript Object Spread. Today I want to highlight a feature of TypeScript that uses a similar syntax, TypeScript Object Rest:


// Here we use object rest to pass a variable number of parameters
function test(a, ...args){
// args is an array of params
if (args.length){
// ....
}
}

As shown in the above example, object rest is a way to pass a variable number of parameters to a function.

Another way to use it is to apply it to objects:


// We create a simple object
let obj = { x: 1, y: 2, z: 3};
let {z, ...obj1} = obj;
// obj1 is now { x: 1, y: 2 }

The above example is a little bit tricky. What it does is initialize a new variable obj1, which is all of obj but z.

In other words, obj1 is the rest of obj minus z. As a result, obj1 only has the x and y properties.

Now we can apply the same syntax to arrays:


// We create a simple array
let arr = [1, 2, 3, 4];
let [first, second, ...arr1] = arr;
// arr1 = [3, 4], first = 1 and second = 2

The above is also called array destructuring.

Now you know everything there is to know about TypeScript Object Rest. It’s a very useful and powerful syntax that brings both clarity and simplicity to your code when needed.