Angular 2 Template Syntax

We have already encountered Angular templates in several earlier chapters. In this article, we will introduce Angular syntax in detail.

The template plays the role of a view; in simple terms, it is the part shown to the user.

  • HTML
  • Interpolation Expression
  • Template Expressions
  • Template Statements
  • Binding Syntax
  • Property Binding
  • HTML Attribute, Class, and Style Binding
  • Event Binding
  • Two-Way Data Binding with NgModel
  • Built-in Directives
  • * and <template>
  • Template Reference Variables
  • Input and Output Properties
  • Template Expression Operators

HTML

HTML is the "language" of Angular templates. Except for the <script> element, which is disabled, all other HTML elements are supported. For example:

<h1>My First Angular App</h1>


Interpolation Expression

The syntax format of interpolation expressions is:{{ ... }}。

Interpolation expressions can insert the computed string into HTML, and can also be used as attribute values.

<h3> {{title}} <img src="{{imageUrl}}" style="height:30px"> </h3>

Template Expressions

{{ ... }}It is actually a template expression. Angular evaluates it and converts it into a string for output.

The following example adds two numbers:

<!-- "The sum of 1 + 1 is 2" --> <p>The sum of 1 + 1 is {{1 + 1}}</p>

We can usegetVal()to get the value of this expression:

<div class="example"> <div class="example_code"> [mycode3 type="html"] <!-- "4" --> <p>{{1 + 1 + getVal()}}</p>

Template expressions are similar to JavaScript. Many JavaScript expressions are also valid template expressions, but not all.

The following JavaScript expressions are prohibited:

  • Assignment expressions (=,+=,-=...)
  • new operator
  • with;or'chaining expressions
  • Increment and decrement operations (++and--) Other notable differences from JavaScript syntax include:
  • Bitwise operators are not supported (|and&)
  • Operators in template expressions, such as|and?.etc., have been given new meanings

Property Binding

Template property binding can set a property of a view element to a template expression.

The most common property binding sets an element's property to the value of a component property. In the following example, the src property of the image element is bound to the component's imageUrl property:

<img [src]="imageUrl">

Disable a button when the component is isUnchanged (unchanged):

<button [disabled]="isUnchanged">The button is disabled</button>

Set the attributes of the directive:

<div [ngClass]="classes">[ngClass] bound to the classes property.</div>

Set a property of a custom component (an important way for communication between parent and child components):

<user-detail [user]="currentUser"></user-detail>

HTML Attribute, Class, and Style Binding

The template syntax provides a special one-way data binding form for scenarios that are not well-suited to property binding.

Attribute Binding

When an element has no property to bind, use HTML attribute binding.

Consider attributes such as ARIA, SVG, and colspan/rowspan in tables. They are purely attributes. They have no corresponding properties to bind.

The following example will raise an error:

<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>

We will get this error:

Template parse errors:
Can't bind to 'colspan' since it isn't a known native property

模板解析错误:不能绑定到'colspan',因为它不是已知的原生属性

As the hint says,<td>Element has nocolspanProperty. But interpolation expressions and property binding can only setProperty, rather than an Attribute, so HTML tag Attribute binding is needed to create and bind similar Attributes.

HTML tag attribute binding is syntactically similar to property binding, but the part in brackets is not an element's property name; instead, it consists of an attr. prefix and the name of an HTML tag attribute, and then the value of the HTML tag attribute is set via an expression that can evaluate to a string. For example:

<table border=1> <tr><td [attr.colspan]="1 + 1">One-Two</td></tr> <tr><td>Five</td><td>Six</td></tr> </table>

CSS Class Binding

With CSS class binding, we can add and remove CSS class names from an element's class attribute.

CSS class binding is syntactically similar to property binding. But the part in square brackets is not an element's property name; instead, it consists of a class prefix, followed by a dot (.), and then a CSS class name. The latter two parts are optional. For example:[class.class-name] 。

The following example shows how to add and remove the "special" class via CSS class binding:

<!--Standard HTML style class setting--> <div class="bad curly special">Bad curly special</div> <!--Reset or override style classes through binding--> <div class="bad curly special" [class]="badCurly">Bad curly</div> <!--Add or remove the special style class based on a property value--> <div [class.special]="isSpecial">This style is special</div>

Style Binding

Through style binding, you can set inline styles. Style binding is syntactically similar to property binding, but the part inside the brackets is not an element's property name; style binding consists of a style. followed by the CSS style property name, for example: [style.style-property].

<button [style.color] = "isSpecial ? 'red': 'green'">Red</button> <button [style.background-color]="canSave ? 'cyan': 'grey'" >Save</button> <!--Style binding with units--> <button [style.font-size.em]="isSpecial ? 3 : 1" >big</button> <button [style.font-size.%]="!isSpecial ? 150 : 50" >small</button>

Style property names can be in kebab-case (font-size) or camelCase (fontSize).


Event Binding

In event binding, Angular responds to the corresponding data flow—from view target to data source—by listening to user actions such as keyboard events, mouse events, touch events, and so on.

The syntax of event binding consists of, inside the parentheses on the left side of the equals sign,target eventand, inside the quotes on the right side,template statement.

For example, the following example is an event binding that listens to the button's click event. Whenever the mouse is clicked, it calls the component'sonSave()method.

<button (click)="onSave()">Save</button>

The name in parentheses—for example (click)—identifies the target event. In the following example, the target is the button's click event.

<button (click)="onSave()">Save</button>

You can also use the on- prefix form:

<button on-click="onSave()">On Save</button>

Two-Way Data Binding with NgModel

When developing data-entry forms, the desired result is to both display the component's data in the form and update the component's data when the user makes changes.

The following is an example of using[(NgModel)]to implement two-way binding:

<input [(ngModel)]="currentUser.firstName">

[] implements data flow from component to template, () implements data flow from template to component, and combining the two [()] implements two-way binding.

Using the prefix form syntax:

<input bindon-ngModel="currentUser.firstName">

Built-in Directives

Angular's built-in directives include NgClass, NgStyle, NgIf, NgFor, NgSwitch, and so on.

NgClass

Dynamically add or remove CSS classes by binding to NgClass.

<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'" >This div is large.</div>

NgStyle

NgStyle, through binding to a key:value control object, allows us to set many inline styles simultaneously.

setStyles() { let styles = { // CSS property name 'font-style': this.canSave ? 'italic' : 'normal', // italic 'font-weight': !this.isUnchanged ? 'bold' : 'normal', // normal 'font-size': this.isSpecial ? '24px' : '8px', // 24px }; return styles; }

By adding an NgStyle property binding that calls setStyles, you can set the element's styles accordingly:

<div [ngStyle]="setStyles()">This div's styles are italic, normal weight, and extra large (24px).</div>

NgIf

By binding the NgIf directive to a truthy expression, you can add an element and its children to the DOM tree.

<div *ngIf="currentUser">Hello,{{currentUser.firstName}}</div>

Conversely, binding to a falsy expression will remove the element and its children from the DOM tree. For example:

<!--Because the value of isActive is false, User Detail is not in the DOM tree.--> <user-detail *ngIf="isActive"></user-detail>

NgSwitch

When you need to conditionally display one element tree from a set of possible element trees, NgSwitch is needed. Angular will only add the selected element to the DOM. For example:

<span [ngSwitch]="userName"> <span *ngSwitchCase="'Zhang San'">Zhang San</span> <span *ngSwitchCase="'Li Si'">Li Si</span> <span *ngSwitchCase="'Wang Wu'">Wang Wu</span> <span *ngSwitchCase="'Zhao Liu'">Zhao Liu</span> <span *ngSwitchDefault>Long Da</span> </span>

The [directive] that serves as the parent directiveNgSwitchis bound to an expression that returns the switch value. In the example, this value is a string, but it can be a value of any type. The parent directiveNgSwitchcontrols a group of<span>child elements. Each<span>is either bound to an expression with a matching value, or marked as the default case. At any time, at most one of these spans will appear in the DOM. If this span's matching value equals the switch value, Angular 2 adds this<span>span to the DOM. If no span matches, Angular 2 adds the default span to the DOM. Angular 2 removes and destroys all other spans.

Three cooperating directives:

  • ngSwitch: bound to an expression that returns the switch value
  • ngSwitchCase: bound to an expression that returns the matching value
  • ngSwitchDefault: an attribute used to mark the default element*, but should use property binding instead, while ngSwitchCase and ngSwitchDefault should be preceded by*。

NgFor

This directive is needed when you need to display a list composed of multiple items. As in the example below, NgFor is applied to an HTML block.

<div *ngFor="let user of users">{{user.fullName}}</div>

NgFor can also be applied to a component element, e.g.:

<user-detail *ngFor="let user of users" [user]="user"></user-detail>

The ngFor directive supports an optional index that grows from 0 to the length of the array during iteration.

This index can be captured through a template input variable and used in the template. The example below captures the index into a variable named i.

<div *ngFor="let user of users; let i=index">{{i + 1}} - {{user.fullName}}</div>

NgForTrackBy

The ngFor directive can sometimes have poor performance, especially in large lists. A small change, removal, or addition to an item will cause cascading DOM operations.

For example, when refreshing the contacts by re-fetching from the server, the refreshed list may contain many (if not all) contacts that were displayed before. But as far as Angular is concerned, it doesn't know which ones existed before, so it can only clear the old list, discard those DOM elements, and rebuild a new list with new DOM elements.

To solve this problem, you can use a tracking function to avoid this hassle. The tracking function tells Angular: we know that two objects with the same user.id are the same contact. For example:

trackByUsers(index: number, user: User){return user.id}

Then, set the NgForTrackBy directive to that tracking function:

<div *ngFor="let user of users; trackBy:trackByUsers">({{user.id}}) {{user.fullName}}</div>

The tracking function does not prevent all DOM changes. If the property used to determine whether it is the same contact changes, the DOM element will be updated; otherwise, this DOM element is left as is. The list interface becomes smoother and more responsive.


Template Reference Variables

Template reference variables are references to DOM elements or directives in the template.

They can be used on native DOM elements and on Angular components—in fact, they work with any custom web component.

We can reference template reference variables on the same element, sibling elements, or any child elements.

Here are two examples of creating and using template reference variables:

<!--phone references the input element and passes `value` to the event handler--> <input #phone placeholder="phone number"> <button (click)="callPhone(phone.value)">Call</button> <!--fax references the input element and passes `value` to the event handler--> <input ref-fax placeholder="fax number"> <button (click)="callFax(fax.value)">Fax</button>

The (#) prefix of "phone" means that we are going to define a variable named phone.

Other extensions