Angular 5 Components & Templates

Angular binding brief introduction

This blog is talking about the template syntax of Angular 5. The reference topic is at https://angular.io/guide/template-syntax.

Angular one-way binding with DOM elements

For DOM elmenets that does simple display, Angular one-way binding is very useful. For example, pure text, or un-editable tables, one-way binding can quick get rendered by directly binding the Angular variable or using *ngFor iteration. There are three examples of one-way binding in the html template. THe binding objective can be expression, which does not change variables.

1
2
3
<p>Hello {{username}}.</p> <!-- pure one-way interpolation with {{}} syntax-->
<input [value]="username"> <!-- DOM property with [] binding -->
bind-target="expression" <!-- bind- prefix target binding-->

** Remember to user [] brackets to make the DOM property actively linked with Angular variables, otherwise the binding is worked as string type initialization only.

Angular two-way binding with DOM elements

For DOM elements that also can have user interactions like input elements, select elments, two-way binding or event binding is required to allow Angular know about the user action. The grammar to bind a two-way variable is to use [(target)].

There are some examples of Angular two-way binding:

1
2
<input [(ngModel)]="username"> <!-- property, like ngModel for form elements, with [()] syntax-->
bindon-target="expression" <!-- bindon- prefix target two-way binding-->

Angular event binding with DOM elements

Some DOM elements are not interact with text but events link click or text change, Angular also provides sytax for event binding so it can track user’s behavior based on DOM events. Vairables, like #event template input variable (let here), and template reference variable (#heroForm), which can be passed to the event handlers. The grammar to bind a event of a DOM is to use parenthesis with Angular event like (click). Event handlers can only be statements like methods of the component instance.

There are some examples of Angular event bindings:

1
2
(click)="click($event)" <!-- use DOM property binding with () syntax-->
on-target="statement" <!-- use on- prefix target binding -->

Angular template binding targets

It’s not hard to see, binding targets in Angular includes HTML properties and events as below table.

Type Target Examples
Property Element property,
Component property,
Directive property
<img [src]="heroImageUrl">
<app-hero-detail [hero]="currentHero"></app-hero-detail>
<div [ngClass]="{'special': isSpecial}"></div>
Event Element event,
Component event,
Directive event
<button (click)="onSave()">Save</button>
<app-hero-detail (deleteRequest)="deleteHero()"></app-hero-detail>
<div (myClick)="clicked=$event" clickable>click me</div>
Two-way Event and property <input [(ngModel)]="name">
Attributes Attribute (the exception) <button [attr.aria-label]="help">help</button>
Class class property <div [class.special]="isSpecial">Special</div>
Style style property <button [style.color]="isSpecial ? 'red' : 'green'">

Besides, Angular also supports built-in directives as below table.

Directive Type Target Use Case Examples
Attribute NgClass add and remove a set of CSS classes <!-- toggle the "special" class on/off with a property -->
<div [class.special]="isSpecial">The class binding is special</div>
Attribute NgStyle add and remove a set of HTML styles <button [style.color]="isSpecial ? 'red' : 'green'">
Attribute NgModel two-way data binding to an HTML form element <input [(ngModel)]="name">
Structural NgIf conditionally add or remove an element from the DOM <app-hero-detail *ngIf="isActive"></app-hero-detail>
Structural NgSwitch a set of directives that switch among alternative views <div *ngFor="let hero of heroes">{{hero.name}}</div>
Structural NgForOf repeat a template for each item in a list <div [ngSwitch]="currentHero.emotion">
<app-happy-hero *ngSwitchCase="'happy'" [hero]="currentHero"></app-happy-hero>
<app-sad-hero *ngSwitchCase="'sad'" [hero]="currentHero"></app-sad-hero>
</div>

Template reference variables

A template reference variable is often a reference to a DOM element within a template. It can also be a reference to an Angular component or directive or a web component.
Use the hash symbol (#) to declare a reference variable. The #phone declares a phone variable on an <input> element.

Example:

1
2
3
4
<input #phone placeholder="phone number">
<!-- lots of other elements -->
<!-- phone refers to the input element; pass its `value` to an event handler -->
<button (click)="callPhone(phone.value)">Call</button>

Template expression operators

The template expression language employs a subset of JavaScript syntax supplemented with a few special operators for specific scenarios. The next sections cover two of these operators: pipe and safe navigation operator.

The pipe operator ( | )

Angular pipes are a good choice for small transformations such as these. Pipes are simple functions that accept an input value and return a transformed value. They’re easy to apply within template expressions, using the pipe operator (|):

Example:

1
<div>Title through uppercase pipe: {{title | uppercase}}</div>

The safe navigation operator ( ?. ) and null property paths

The Angular safe navigation operator (?.) is a fluent and convenient way to guard against null and undefined values in property paths. Here it is, protecting against a view render failure if the currentHero is null.

Example:

1
The current hero's name is {{currentHero?.name}}

The Angular non-null assertion operator (!) serves the same purpose in an Angular template.

Example:

1
2
3
4
5
<!--No hero, no text -->
<div *ngIf="hero">
The hero's name is {{hero!.name}}
</div>

The $any type cast function ($any( ))

Sometimes a binding expression will be reported as a type error and it is not possible or difficult to fully specify the type. To silence the error, you can use the $any cast function to cast the expression to the any type.

1
2
3
4
<!-- Accessing an undeclared member -->
<div>
The hero's marker is {{$any(hero).marker}}
</div>

Angular binding different component properties

We usually binding a template to its own component class. In such binding expressions, the component’s property or method is to the right of the (=).

The Angular compiler won’t bind to properties of a different component unless they are Input or Output properties. You can’t use the TypeScript public and private access modifiers to shape the component’s public binding API.

Declaring Input and Output properties

An Input property is a settable property annotated with an @Input decorator. Values flow into the property when it is data bound with a property binding
An Output property is an observable property annotated with an @Output decorator. The property almost always returns an Angular EventEmitter. Values flow out of the component as events bound with an event binding.

Example:

In the sample for this guide, the bindings to HeroDetailComponent do not fail because the data bound properties are annotated with @Input() and @Output() decorators.

In src/app/app.component.html file, below code will through compile error as template of app component does not recognize the property of hero-detail component:

1
2
<app-hero-detail [hero]="currentHero" (deleteRequest)="deleteHero($event)">
</app-hero-detail>

In src/app/hero-detail.component.ts file, set @Input and @Output decorator with corresponding properties. Then the error is resolved.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...

@Component({
inputs: ['hero'],
outputs: ['deleteRequest'],
})

...

@Input() hero: Hero;
@Output() deleteRequest = new EventEmitter<Hero>();

...