Angular2 series – Template Syntax

This post is part of a series of posts about Angular2. You can find them all in the introduction: http://julienrenaux.fr/2015/11/30/angular2-series-introduction/


Before we start and to make sure we are in line on the terminology, I will use the name AngularJS to define AngularJS 1.x and Angular2 to define AngularJS 2.x.

To understand the code blocks in that Angular2 series of posts, we need to learn a bit about the new Angular2 template syntax.

Be careful, as of alpha52 core directives syntax changes from kebab case to camel case. Example: ng-if becomes ngIf. For more information read the migration docs

Bind property

AngularJS

With AngularJS, binding a given expression to a property value requires to use either a core directive such as ng-value or use AngularJS markup {{}}.

ng-value is expecting an AngularJS expression, whose value will be bound to the value attribute of the input element:

<input ng-value="firstName" />

But you could also use it that way:

<input value="{{firstName}}" />

Angular2

With Angular2 it is similar, without the need to use a specific directive. Only the new syntax is necessary [value] and it is not limited to value, you can use it to bind anything to any particular element property:

<input [value]="firstName" [placeholder]="firstNamePlaceholder" />

Exactly like AngularJS you can use the following:

<input value="{{firstName}}" placeholder="{{firstNamePlaceholder}}" />

Event

AngularJS

With AngularJS we need to use special directives to listen to events. The most famous being ng-click. Ng-click listen to the onClick event. Here is the list of all the HMTL5 events that you can normally listen to: http://www.w3schools.com/tags/ref_eventattributes.asp

Most of the HTML5 events are covered by AngularJS directives such as ng-blur, ng-change, ng-focus, ng-keyup etc.

<button ng-click="doSomething($event)">

Angular2

With Angular2 you can listen to any HTML5 native element event using this special syntax: (eventName)

<button (click)="doSomething($event)">

Two-way data binding

Angular2 also has a two-way data binding in place but do not use the famous and decried “digest cycle” of AngularJS. Instead, Angular2 uses zone.js.

A zone is an execution context that persists across async tasks.

If you want to make sense out of this sentence I suggest you watch this talk by Brian Ford:

Basically zone.js gives Angular2 a low level foundation that let it instrument the browser and let it know when asynch operations are finished.

That way, you can combine event and bind property syntaxes that we saw before:

<input type="text" [value]="firstName" (input)="firstName=$event.target.value" />

That being said, ngModel can be used as a simplified version of what we have above:

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

The result is identical.

Pro tip: you can also run anything outside the Angular2 zone using the NgZone service. The most common use of this service is to optimize performance when starting a work consisting of one (or more) asynchronous task that does not require UI updates.


Local variable

A local template variable is a vehicle for moving data across element lines. As far as I know, there is no equivalent of local variable in AngularJS. A local variable # can be a pointer to an object or an DOM element.

<video #movieplayer ...>
  <button (click)="movieplayer.play()">
</video>

In the above example, having the movieplayer allows us to manipulate the video HTML5 api on the same element, its siblings or its children.

Pro tip: # is the canonical version of the local variable. You can also use it with var-. In our movieplayer case we could have var-movieplayer instead of #movieplayer.


* symbol

This is probably the most disturbing syntax choice of the new Angular2 syntax. It is actually pretty simple to understand what it does if you have a little background on what the template tag is.

template tag

The template tag allows you to declare a piece of DOM that can be instantiated after run time. It guaranties better performance and the usage of a resource only when needed.

Here is an example to be clearer:

<div style="display:none">
  <img src="path/to/your/image.png" />
</div>

As you can see, the image will not be displayed because of display:none on its parent. The problem is that the browser will prefetch this image whether you use it or not. It is a waste of resource and can impact your page performance.

The solution to this very problem is to use the template tag!

<template>
  <img src="path/to/your/image.png" />
</template>

The image in the above example will not be fetch by the browser until we instantiate the template.

Let’s get back to the * symbol now. Using it on a element will turn it into an embedded template:

<hero-detail *ngIf="isActive" [hero]="currentHero"></hero-detail>

The following will be transformed as:

<template [ngIf]="isActive">
  <hero-detail [hero]="currentHero"></hero-detail>
</template>

Now that I explained what the template tag is for, it is easy to understand that the * symbol is used by conditional directives such as ngFor, ngIf, and ngSwitch. Indeed, <hero-detail> component does not need to be instantiated until isActive is true.


Pipe

A pipe in Angular2 is the equivalent of filters in AngularJS. As in AngularJS, pipes can be stateless (pure functions, not reevaluated) or stateful (has dependencies that can modify the output).

Stateful

In Angular2, most built-in pipes are stateless, it is the case with DatePipe, UpperCasePipe, LowerCasePipe, CurrencyPipe, and PercentPipe.

You can use them that way:

<p>My birthday is {{ birthday | date:"MM/dd/yy" }} </p>

and even chain them (same as AngularJS):

{{ birthday | date | uppercase}}

Stateful

The Async pipe is a built-in stateful pipe. It can receive a Promise or Observable as input and subscribe to the input automatically, eventually returning the emitted value(s).

@Component({
  selector: 'my-hero',
  template: 'Message: {{delayedMessage | async}}',
})
class MyHeroAsyncMessageComponent {
  delayedMessage:Promise<string> = new Promise((resolve, reject) => {
    setTimeout(() => resolve('You are my Hero!'), 500);
  });
}

Here, <my-hero> component will display Message: You are my Hero! only once the delayedMessage promise is resolved.


Elvis operator

In JavaScript, you often end up checking the existence of object properties. For instance I am sure you have written that kind of conditions before:

if (cordova && cordova.plugins && cordova.plugins.notification){
  // use cordova.plugins.notification
}

All of this to avoid such an error TypeError: Cannot read property 'notification' of undefined.

Pro tip: you can simplify it using lodash _.get function. The previous example could be written that way:

if (_.get(cordova, 'plugins.notification')){
  // use cordova.plugins.notification
}

Even if plugins is not defined _.get will return undefined.

The Elvis operator (?) in Angular2 fixes that very problem but in the template side.

<p>Employer: {{employer?.companyName}}</p>

Here the employer field is optional and if undefined, the rest of the expression should be ignored. Without the Elvis operator here you will get a TypeError.

It also works with long property path: a?.b?.c?.d


Thanks for reading, you can interact about this post by leaving a comment here, or directly on Twitter and Facebook!

Leave a Reply

Your email address will not be published. Required fields are marked *