The Road to Angular 2.0 part 1: Template Syntax

Intro

A couple of weeks ago I gave a presentation at the GOTO conference in Amsterdam titled: The Road to Angular 2.0, in this presentation, I walked the Road to Angular 2.0 to figure out why Angular 2.0 was so different from 1.x.

This series of blogposts is a follow up to that presentation.

The Road

When the first details about Angular 2.0 emerged, my initial response was: "Wait, what?!" So many things will change from version 1.x to 2.0, is it even Angular?

So I started digging through design documents, meeting notes, blogposts, and watched ng-conf videos. I quickly discovered a theme: The web will fundamentally change and Angular must evolve with it.

Web Components are coming, ES6 is around the corner, TypeScript was invented. This series of blog posts takes you through these new innovations and shows you how they have influenced Angular 2.0’s design.

I like to visualise all of the changes from Angular 1.x to 2.0 as a road. On this road we will come past various places that represent changes to Angular 1.x. Throughout this series of blog posts we will visit each of these places, and dive into how and why they have influenced Angular 2.0’s design. Here is the Road to Angular 2.0:


theroadtoangular


Template Syntax

Angular 2.0 has a new template syntax, which is radically different from 1.x. These changes made to the template syntax caused a strong negative reaction amongst the Angular community. It seemed like the Angular teams changed the heart of Angular for no good reason.

Now it seems we must learn Angular 2.0 all over again. But fear not, once you understand how the new template syntax works, and you know the reasoning behind it, it will make sense.

The new binding syntax

Let's look at the differences in the bindings syntax between the two versions of Angular:

Angular 1.x

    <span>Username: {{user.username}}</span>
    <img ng-src="{{ user.imageUrl }}"/>
    <button ng-click="upvote(user)">+1</button>
  
Angular 2.0

    <span>Username: {{user.username}}</span>
    <img [src]="{{ user.imageUrl }}"/>
    <button (click)="upvote(user)">+1</button>
The example above shows a username an image and an up-vote button.

The first thing to note is that the first line is exactly the same in 1.x and 2.0. String interpolation is here to stay, so at least that part is still familiar.

The second line of code shows us the first difference in the new template syntax. Instead of using the ng-src directive in Angular 2.0 we see [src]. The brackets represent a binding to a property, this means that when the value changes in the “controller” the value is updated in the view as well.

The third line shows the new event syntax, whereas we used the special ng-click directive in 1.x we simply surround the event by parenthesis in 2.0.

Why change the binding syntax?

The main reason the syntax changed is unification. Lets look at the following line of 1.x template code:

<img ng-src="{{ user.imageUrl }}"/>

In this code we use ng-src to fetch a template. If you take a step back from Angular and look at the code as a novice, who doesn’t know Angular,  you could ask: Why not simply write:

<img src="{{ user.imageUrl }}"/>
The reason of course is that the browser will try to fetch: {{ user.imageUrl }} from the server. This is because the browser doesn’t understand Angular’s string interpolation syntax.

So in Angular 1.x the team worked around this by introducing ng-src. The browser doesn’t recognize ng-src as the property that represents url to the image, so it leaves it alone. Angular can then, under the hood, write the actual "src" property once the binding can be resolved.

In Angular 1.x ng-src is not the only directive that does this, in fact there are many more: ng-blur, ng-click, ng-hide, ng-show, ng-disabled, ng-selected. All of these directives were made so Angular doesn’t get in the browsers way and vice versa. So for each property the browser has, a corresponding Angular directive exists.

Why is this so bad, let's say for example that tomorrow all browsers include the following way to include HD images:

<img src-hd="hd-car.png" src="car.png"/>

What does Angular 1.x have to do to make that work? Write a specialized directive of course! In an ideal world Angular would work with new HTML properties out of the box, without having to change Angular’s code.

In Angular 2.0 the core team decided to tackle this problem at the root. By making one unified syntax for all properties. That’s where the bracket and parenthesis come from. So looking at the following line of code again:

<img [src]="{{ user.imageUrl }}"/>

I would like to read this as: Create a property called "src" with the value of the expression, and update it whenever the value changes. The part between the brackets: "src" is just the name of the property Angular 2.0 must render on the HTML element.

So if "src-hd" was introduced tomorrow, I could write this in Angular 2.0:

<img [src-hd]="hd-car.png" [src]="car.png"/>

The best part is that, unlike Angular 1.x, Angular 2.0 would not have to be updated itself. So Angular 2.0’s template syntax unifies all of the built in directives from Angular 1.x into one syntax.

Benefits of the new binding syntax

The first benefit as you have already read is that Angular 2.0’s template syntax is more future proof than Angular 1.x’s.

The new syntax is also easier to learn for beginners. If you already know HTML and you work as a web designer and suddenly you are dropped in an Angular 2.0 project, you simply need to learn to write square brackets around HTML properties you already know. There is no more need to learn al of these specific cases such as ng-src. The new syntax is simply closer to HTML than before.

Another benefit of the new syntax is that it is easier to reason about. What I mean by reasoning is that it is easier to understand a template just by reading it. For example what does "selected" do in this Angular 1.x directive?

<google-map selected="markers(marker)"></google-map>

It could mean one of the following things:
  1. It selects a certain marker based on the outcome of function "markers".
  2. It is an event that executes a callback to "markers” whenever a marker is selected.
  3. The "selected" property is a two way binding that changes through the "markers” function.
In order to know which one of the above answers is correct you would have to read the definition of the google-map directive.

If this was an Angular 2.0 template:

<google-map (selected)="markers(marker)"></google-map>

Now it is immediately clear that "selected" is an event because of the parenthesis. You would not have to read all of the surrounding code to understand what something does.

Local Variables

Angular 2.0 templates brings us a new feature that was not previously seen in Angular 1.x. This feature is called local variables, it allows us to create variables that are only available in a specific template.

The reason for wanting to create variables that are only visible in your template is so you can create multiple templates for the same "controller". Imagine if you had to make a page with a YouTube player component, that needs to work on mobile and desktop. You discover two great Web Components: one that works great on desktop and another that works great on mobile devices. So you create two templates: one for desktop and one for mobile. But now you might need two controllers, because you have two different youtube components, right? The answer is no, because Angular 2.0 allows you to create 'variables' directly in your template.

The syntax for creating a local variable is simply a name and a hashtag.

Lets look at an fictitious example of the mobile template:

<youtube-mobile #player></youtube-mobile>
<button (click)="player.startVideo('Maarten's Baptism')">Play</button>

Now take a look the desktop's version of the template:

<youtube-embedded #player hd="yes"></youtube-embedded>
<button (click)="player.run('Maarten's Baptism')">Play</button>

In both cases you can see we define a local variable called #player which we use to reference the 'player' HTML elements. In the play buttons we can then reference "player" in the (click) event to start a video. Note that the API to start a video is different between the desktop and mobile version. So even though the API is different we didn't have to touch the controller at all, thats the power of local variables!

Templates

Angular 2.0 also introduces a new concept called 'directive templates', a directive template manipulates HTML. Lets look at an example:

<ul>
  <li *ng-for="#name of names">Username: {{name}}</li>
</ul>

If you know Angular 1.x you will find *ng-for familiar, it does what ng-repeat used to do. *ng-for manipulates the HTML by repeating the HTML element for N times.

Note that we create a local variable called #name that we reference inside of the <li> element. The #name variable is only available inside of the <li> element, because it is scoped to the template.

Another example of a template is *ng-if:

<div *ng-if="todos.length === 0">You are done!</div>


The reason this is called a 'template' is because behind the scene's Angular 2.0 will convert the code to a <template> tag. So the *ng-for example would expand to:

<template ng-for #name="$implicit" [ng-for-of]="name">
  <li>{{name}}</li>
</template>

A <template> element represents an inert piece of DOM that the browser will completely ignore. This gives frameworks such as Angular an easy way to define templates, without the browser trying to parse them and mess with them. The <template> element was basically created for use by JavaScript frameworks.

The benefits of the new *template syntax is that your IDE and text-editor can analyse these final <template> forms of the directive. This means that they can autocomplete your code and provide your with better help. This will ultimately make us developers that use Angular 2.0 more productive.

Codifying the new syntax

We can codify the new syntax as follows:

Property bindings []
Square brackets represent a property which has a binding to a value. This binding is always an expression. Angular evaluates it every time inside the run loop when it is dirty checking for changes. Whenever a change is detected the binding is updated.

The expressions should be  pure: each time they are evaluated with the same parameters they should return the same value. They should not cause side effects.

Events ()
Parenthesis represent events. Events handlers are statements, which cause side effects. The events always originate from actions taken by the user, such as: hovering the mouse or typing on the keyboard.

Variables #
Hashtags represent local variables. These are only available inside of the template where they are defined. They can be used so different templates for mobile and desktop can contain completely different pieces of code, but still keep the same controller.

Templates *
An asterisk represents a template with your HTML that is expanded to a <template> element behind the scenes. They were created so IDE's and text editors can better autocomplete the code.

Conclusion

The new syntax makes it easier for newcomers to learn, because it more closely resembles HTML, and because you do not have to learn the built in templates. It also makes it easier to reason about templates so we can more easily discover what a template does.
Next week we will take a look at ES6, the new version of JavaScript, and how it affects Angular 2.0.