Template Syntax

Template Syntax

Our Angular application manages what the user sees and does through the interaction of a Component class instance and its user-facing template.

Many of us are familiar with the Component/Template duality from our experience with Model-View-Controller or Model-View-ViewModel. In Angular, the Component plays the part of the Controller/ViewModel and the Template represents the view.

Let’s find out what it takes to write a Template for our view.

We’ll cover these basic elements of Template Syntax

HTML

Interpolation

Template expressions

Binding syntax

Property Binding

Attribute, Class and Style Bindings

Event Binding

Two-way data binding with NgModel

Built-in Directives

* and <template>

Local template variables

Input and Output Properties

Template Expression Operators

Live Example.

HTML

HTML is the language of the Angular template. Our “QuickStart” application had a template that was pure HTML

<h3>My First Angular Application</h3>

Almost all HTML syntax is valid template syntax. The <script> element is a notable exception; it is forbidden in order to eliminate any possibility of JavaScript injection attacks (in practice it is simply ignored).

Some legal HTML doesn’t make much sense in a template. The <html>, <body> and <base> elements have no useful role in our repertoire. Pretty much everything else is fair game.

We can extend the HTML vocabulary of our templates with Components and Directives that appear as new elements and attributes. And we are about to learn how to get and set DOM values dynamically through data binding.

Let’s turn to the first form of data binding - interpolation - to see how much richer Template HTML can be.

Interpolation

We met the double-curly braces of interpolation, {{ and }}, early in our Angular education.

<p>My current hero is {{currentHero.firstName}}</p>

We use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments.

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

The material between the braces is often the name of a component property. Angular replaces that name with the string value of the corresponding component property. In this example, Angular evaluates the title and heroImageUrl properties and "fills in the blanks", displaying first a bold application title and then a heroic image.

More generally, the material between the braces is a template expression that Angular first evaluates and then converts to a string. The following interpolation illustrates the point by adding the two numbers within braces:

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

The expression can invoke methods of the host component as we do here with getVal():

<!-- "The sum of 1 + 1 is not 4" --> <p>The sum of 1 + 1 is not {{1 + 1 + getVal()}}</p>

Angular evaluates all expressions in double curly braces, converts the expression results to strings, and concatenates them with neighboring literal strings. Finally, it assigns this composite interpolated result to an element or directive property.

We appear to be inserting the result between element tags and assigning to attributes. It's convenient to think so and we rarely suffer for this mistake. But it is not literally true. Interpolation is actually a special syntax that Angular converts into a Property Binding as we explain below. The implications and consequences can be profound.

But before we explore that assertion, we’ll take a closer look at template expressions.

Template Expressions

We saw a template expression within the interpolation braces. We’ll see template expressions again in Property Bindings ([property]="expression") and Event Bindings ((event)="expression").

A template expression is a JavaScript-like expression. Many JavaScript expressions are legal template expressions but not all and there are a few language extensions. Notable differences include:

Perhaps more surprising, we cannot refer to anything in the global namespace. We can’t refer to window or document. We can’t call console.log. We are restricted to referencing members of the expression context.

The expression context is typically the component instance supporting a particular template instance.

We speak of component and template instances. Angular creates multiple concrete instances from a component class and its template.

For example, we may define a component and template to display a list item and tell Angular to create new instances of that component/template pair for each item in a list. There’s a separate, independent expression context for each item in that list as well.

When we see title wrapped in double-curly braces, {{ }}., we know that it is a property of a parent component. When we see [disabled]="isUnchanged" or (click)="onCancel()”, we know we are referring to that component's isUnchanged property and onCancel method respectively.

The component itself is usually the expression context in which case the template expression usually references that component. The expression context may include an object other than the component.

A local template variable is one such supplemental context object; we’ll discuss that option below.

Another is the $event variable that contains information about an event raised on an element; we’ll talk about that when we consider Event Bindings.

Although we can write quite complex template expressions, we strongly discourage that practice. Most readers frown on JavaScript in the HTML. A property name or method call should be the norm. An occasional Boolean negation (!) is OK. Otherwise, confine application and business logic to the component itself where it will be easier to develop and test.

Now that we have a feel for template expressions, we’re ready to learn about the varieties of data binding syntax beyond Interpolation.

Binding syntax overview

Data binding is a mechanism for coordinating what users see with application data values. While we could push values to and pull values from HTML, the application is easier to write, read, and maintain if we turn these chores over to a binding framework. We simply declare bindings between the HTML and the data properties and let the framework do the work.

Angular provides many kinds of data binding and we’ll discuss each of them in this chapter. First we'll take a high level view of Angular data binding and its syntax.

We can group all bindings into three categories by the direction in which data flows. Each category has its distinctive syntax:

Data DirectionSyntaxBinding Type
One way
from data source
to view target
{{expression}} [target] = "expression" bind-target = "expression"Interpolation
Property
Attribute
Class
Style
One way
from view target
to data source
(target) = "expression" on-target = "expression"Event
Two way[(target)] = "expression" bindon-target = "expression"Two-way

Template expressions must be surrounded in quotes except for interpolation expressions which must not be quoted.

All binding types except interpolation have a target name to the left of the equal sign, either surrounded by punctuation ([], ()) or preceded by a prefix (bind-, on-, bindon-).

What is that target? Before we can answer that question, we must challenge ourselves to look at Template HTML in a new way.

A New Mental Model

With all the power of data binding and our ability to extend the HTML vocabulary with custom markup, it is tempting to think of Template HTML as “HTML Plus”. Well it is “HTML Plus”.

But it’s also significantly different than the HTML we’re used to. We really need a new mental model.

In the normal course of HTML development, we create a visual structure with HTML elements and we modify those elements by setting element attributes with string constants.

<div class="special">Mental Model</div> <div><b>{{currentHero.fullName}}</b></div> <img src="images/hero.png"> <button disabled>Save</button>

We still create a structure and initialize attribute values this way in Angular templates.

Then we learn to create new elements with Components that encapsulate HTML and drop them into our templates as if they were native HTML elements

<div class="special">Mental Model</div> <hero-detail></hero-detail>

That’s “HTML Plus”.

Now we start to learn about data binding. The first binding we meet might look like this:

<!-- Bind button disabled state to `isUnchanged` property --> <button [disabled]="isUnchanged">Save</button>

We’ll get to that peculiar bracket notation in a moment. Looking beyond it, our intuition tells us that we’re binding to the button's disabled attribute and setting it to the current value of the component’s isUnchanged property.

Our intuition is wrong! Our everyday HTML mental model is misleading us. In fact, once we start data binding, we are no longer working with HTML attributes. We aren't setting attributes. We are setting the properties of DOM elements, Components, and Directives.

HTML Attribute vs. DOM Property

The distinction between an HTML attribute and a DOM property is crucial to understanding how Angular binding works.

Attributes are defined by HTML. Properties are defined by DOM (the Document Object Model).

That last category can be especially confusing ... until we understand this general rule:

Attributes initialize DOM properties and then they are done. Property values may change; attribute values don't.

For example, when the browser renders <input type="text" value="Bob">, it creates a corresponding DOM node with a value property initialized to "Bob".

When the user enters "Sally" into the input box, the DOM element value property becomes "Sally". But the HTML value attribute remains unchanged as we discover if we ask the input element about that attribute: input.getAttribute('value') // returns "Bob"

The HTML attribute value specifies the initial value; the DOM value property is the current value.

The disabled attribute is another peculiar example. A button's disabled property is false by default so the button is enabled. When we add the disabled attribute, it's presence alone initializes the button's disabled property to true so the button is disabled.

Adding and removing the disabled attribute disables and enables the button. The value of the attribute is irrelevant which is why we cannot enable a button by writing <button disabled="false">Still Disabled</button>.

Setting the button's disabled property (e.g. with an Angular binding) disables or enables the button. The value of the property matters.

The HTML attribute and the DOM property are not the same thing even when they have the same name.

This is so important, we’ll say it again.

Template binding works with properties and events, not attributes.

A world without attributes

In the world of Angular 2, the only role of attributes is to initialize element and directive state. When we data bind, we're dealing exclusively with element and directive properties and events. Attributes effectively disappear.

With this model firmly in mind, we are ready to discuss the variety of target properties to which we may bind.

Binding Targets

The target of a data binding is something in the DOM. Depending on the binding type, the target can be an (element | component | directive) property, an (element | component | directive) event, or (rarely) an attribute name. The following table summarizes:

Binding TypeTargetExamples
PropertyElement Property
Component Property
Directive property
<img [src] = "heroImageUrl"> <hero-detail [hero]="currentHero"></hero-detail> <div [ngClass] = "{selected: isSelected}"></div>
EventElement Event
Component Event
Directive Event
<button (click) = "onSave()">Save</button> <hero-detail (deleted)="onHeroDeleted()"></hero-detail> <div myClick (myClick)="clicked=$event">click me</div>
Two-wayDirective Event Property<input [(ngModel)]="heroName">
AttributeAttribute (the exception)<button [attr.aria-label]="help">help</button>
Classclass Property<div [class.special]="isSpecial">Special</div>
Stylestyle Property<button [style.color] = "isSpecial ? 'red' : 'green'">

Let’s descend from the architectural clouds and look at each of these binding types in concrete detail.

Property Binding

We write a template Property Binding when we want to set a property of a view element to the value of a template expression.

The most common Property Binding sets an element property to a component property value as when we bind the source property of an image element to the component’s heroImageUrl property.

<img [src]="heroImageUrl">

… or disable a button when the component says that it isUnchanged.

<button [disabled]="isUnchanged">Cancel</button>

… or set a property of a directive

<div [ngClass]="'special'">NgClass is special</div>

… or set the model property of a custom component (a great way for parent and child components to communicate)

<hero-detail [hero]="selectedHero"></hero-detail>

People often describe Property Binding as “one way data binding” because it can flow a value in one direction, from a component’s data property to an element property.

Binding Target

A name between enclosing square brackets identifies the target property. The target property in this example is the image element’s src property.

<img [src]="heroImageUrl">

Some developers prefer the bind- prefix alternative, known as the “canonical form”:

<img bind-src="heroImageUrl">

The target name is always the name of a property, even when it appears to be the name of something else. We see src and may think it’s the name of an attribute. No. It’s the name of an image element property.

Element properties may be the more common targets, but Angular looks first to see if the name is a property of a known directive as it is in the following example:

<div [ngClass]="'special'">NgClass is special</div>

Technically, Angular is matching the name to a directive input, one of the property names listed in the directive’s inputs array or a property decorated with @Input(). Such inputs map to the directive’s own properties.

If the name fails to match a property of a known directive or element, Angular reports an “unknown directive” error.

Property Binding template expressions

Evaluation of the expression should have no visible side-effects. The expression language itself does its part to keep us safe. We can’t assign a value to anything in a Property Binding expression nor use the increment and decorator operators.

Of course, our expression might invoke a property or method that has side-effects. Angular has no way of knowing that or stopping us.

The expression could call something like getFoo(). Only we know what getFoo() does. If getFoo() changes something and we happen to be binding to that something, we risk an unpleasant experience. Angular may or may not display the changed value. Angular may detect the change and throw a warning error. Our general advice: stick to data properties and methods that return values and do no more.

The template expression should evaluate to a value of the type expected by the target property. Most native element properties do expect a string. The image src should be set to a string, an URL for the resource providing the image. On the other hand, the disabled property of a button expects a Boolean value so our expression should evaluate to true or false.

The hero property of the HeroDetail component expects a Hero object which is exactly what we’re sending in the Property Binding:

<hero-detail [hero]="selectedHero"></hero-detail>

This is good news for the Angular developer. If hero were an attribute we could not set it to a Hero object.

<!-- Doesn't work! HeroDetailComponent expects a Hero, not a string --> <hero-detail hero="…what do we do here??? …"></hero-detail>

We can't set an attribute to an object. We can only set it to a string. Internally, the attribute may be able to convert that string to an object before setting the like-named element property. That’s good to know but not helpful to us when we're trying to pass a significant data object from one component element to another. The power of Property Binding is its ability to bypass the attribute and set the element property directly with a value of the appropriate type.

Property Binding or Interpolation?

We often have a choice between Interpolation and Property Binding. The following binding pairs do the same thing

<img src="{{heroImageUrl}}"> <img [src]="'' + heroImageUrl"> <div>The title is {{title}}</div> <div [textContent]="'The title is '+title"></div>

Interpolation is actually a convenient alternative for Property Binding in many cases. In fact, Angular translates those Interpolations into the corresponding Property Bindings before rendering the view.

There is no technical reason to prefer one form to the other. We lean toward readability which tends to favor interpolation. We suggest establishing coding style rules for the organization and choosing the form that both conforms to the rules and feels most natural for the task at hand.

Attribute, Class, and Style Bindings

The template syntax provides specialized one-way bindings for scenarios less well suited to Property Binding.

Attribute Binding

We can set the value of an attribute directly with an Attribute Binding.

This is the only exception to the rule that a binding sets a target property. This is the only binding that creates and sets an attribute.

We have stressed throughout this chapter that setting an element property with a Property Binding is always preferred to setting the attribute with a string. Why does Angular offer Attribute Binding?

We must use Attribute Binding when there is no element property to bind.

Consider the aria, svg, and table span attributes. They are pure attributes. They do not correspond to element properties and they do not set element properties. There are no property targets to bind to.

We become painfull aware of this fact when we try to write something like this:

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

… and get the error:

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

As the message says, the <td> element does not have a colspan property. It has the "colspan" attribute but interpolation and property binding can only set properties, not attributes.

We need an Attribute Binding to create and bind to such attributes.

Attribute Binding syntax resembles Property Binding. Instead of an element property between brackets, we start with the keyword attr followed by the name of the attribute and then set it with an expression that resolves to a string.

Here we bind [attr.colspan] to a calulated value:

<table border=1> <!-- expression calculates colspan=2 --> <tr><td [attr.colspan]="1 + 1">One-Two</td></tr> <!-- ERROR: There is no `colspan` property to set! <tr><td colspan="{{1 + 1}}">Three-Four</td></tr> --> <tr><td>Five</td><td>Six</td></tr> </table>

Here's how the table renders:

One-Two
FiveSix

One of the primary use cases for the Attribute Binding is to set aria attributes as we see in this example

<!-- create and set an aria attribute for assistive technology --> <button [attr.aria-label]="actionName">{{actionName}} with Aria</button>

Class Binding

We can add and remove CSS class names from an element’s class attribute with the Class Binding.

Class Binding syntax resembles Property Binding. Instead of an element property between brackets, we start with the keyword class followed by the name of a CSS class: [class.class-name].

In the following examples we see how to add and remove the application's "special" class with class bindings. We start by setting the attribute without binding:

<!-- standard class attribute setting --> <div class="bad curly special">Bad curly special</div>

We replace that with a binding to a string of the desired class names; this is an all-or-nothing, replacement binding.

<!-- reset all class names with a string binding --> <div class="bad curly special" [class]="'bad curly'">Bad curly</div>

Finally, we bind to a specific class name. Angular adds the class when the template expression evaluates to something truthy and removes the class name when the expression is falsey.

<!-- toggle the "special" class on/off with a property --> <div [class.special]="isSpecial">The class binding is special</div> <!-- binding to `class.special` trumps the class attribute --> <div class="special" [class.special]="!isSpecial">This one is not so special</div>

While this is a fine way to toggle a single class name, we generally prefer the NgClass directive for managing multiple class names at the same time.

Style Binding

We can set inline styles with a Style Binding.

Style Binding syntax resembles Property Binding. Instead of an element property between brackets, we start with the key word style followed by the name of a CSS style property: [style.style-property].

<button [style.color] = "isSpecial ? 'red' : 'green'">Red</button> <button [style.backgroundColor]="canSave ?'cyan' : 'grey'" >Save</button>

Some Style Binding styles have unit extension. Here we conditionally set the fontSize in “em” and “%” units .

<button [style.fontSize.em]="isSpecial ? 3 : 1" >Big</button> <button [style.fontSize.%]="!isSpecial ? 150 : 50" >Small</button>

While this is a fine way to set a single style, we generally prefer the NgStyle directive when setting several inline styles at the same time.

Event Binding

The bindings we’ve met so far flow data in one direction from the component to an element.

Users don’t just stare at the screen. They enter text into a input box. They pick items from a list. They click buttons. Such user actions may result in a flow of data in the opposite direction, from an element to the component.

The only way to know about a user action is to listen for certain events such as keystrokes, mouse movements, clicks and touches. We declare our interest in user actions through Angular Event Binding.

The following Event Binding listens for the button’s click event and calls the component's onSave() method:

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

Event Binding syntax consists of a target event on the left of an equal sign and a template expression on the right: (click)="onSave()"

Binding target

A name between enclosing parentheses identifies the target event. In the following example, the target is the button’s click event.

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

Some developers prefer the on- prefix alternative, known as the “canonical form”:

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

Element events may be the more common targets, but Angular looks first to see if the name matches an event property of a known directive as it does in the following example:

<!-- `myClick` is an event on the custom `MyClickDirective` --> <div myClick (myClick)="clickity=$event">click with myClick</div>

If the name fails to match an element event or an output property of a known directive, Angular reports an “unknown directive” error.

$event and event handling expressions

In an Event Binding, Angular sets up an event handler for the target event.

When the event is raised, the handler executes the template expression. The template expression typically involves a receiver that wants to do something in response to the event such as take a value from the HTML control and store it in a model.

The binding conveys information about the event including data values through an event object named $event.

The shape of the $event object is determined by the target event itself. If the target event is a native DOM element event, the $event is a DOM event object with properties such as target and target.value.

Consider this example:

<input [value]="currentHero.firstName" (input)="currentHero.firstName=$event.target.value" >

We’re binding the input box value to a firstName property and we’re listening for changes by binding to the input box’s input event. When the user makes changes, the input event is raised, and the binding executes the expression within a context that includes the DOM event object, $event.

We must follow the $event.target.value path to get the changed text so we can update the firstName

If the event belongs to a directive (remember: components are directives), $event has whatever shape the directive chose to produce. Consider a HeroDetailComponent that produces deleted events with an EventEmitter.

HeroDetailComponent.ts (excerpt)
deleted = new EventEmitter<Hero>(); onDelete() { this.deleted.emit(this.hero); }

When something invokes the onDeleted() method, we "emit" a Hero object.

Now imagine a parent component that listens for that event with an Event Binding.

<hero-detail (deleted)="onHeroDeleted($event)" [hero]="currentHero"> </hero-detail>

The event binding surfaces the hero-to-delete emitted by HeroDetail to the expression via the $hero variable. We pass it along to the parent onHeroDeleted() method. That method presumably knows how to delete the hero.

Evaluation of an Event Binding template expression may have side-effects as this one clearly does. They are not just OK (unlike in property bindings); they are expected.

The expression could update the model thereby triggering other changes that percolate through the system, changes that are ultimately displayed in this view and other views. The event processing may result in queries and saves to a remote server. It's all good.

Event bubbling and propagation

Angular invokes the event-handling expression if the event is raised by the current element or one of its child elements.

<div class="parent-div" (click)="onClickMe($event)">Click me <div class="child-div">Click me too!</div> </div>

Many DOM events, both native and custom, “bubble” events up their ancestor tree of DOM elements until an event handler along the way prevents further propagation.

EventEmitter events don’t bubble.

The result of an Event Binding expression determines if event propagation continues or stops with the current element.

Event propagation stops if the binding expression returns a falsey value (as does a method with no return value). Clicking the button in this next example triggers a save; the click doesn't make it to the outer <div> so it's save is not called:

<!-- Will save only once --> <div (click)="onSave()"> <button (click)="onSave()">Save, no propagation</button> </div>

Propagation continues if the expression returns a truthy value. The click is heard both by the button and the outer <div>, causing a double save:

<!-- Will save twice --> <div (click)="onSave()"> <button (click)="onSave() || true">Save w/ propagation</button> </div>

Two-Way Binding with NgModel

When developing data entry forms we often want to both display a data property and update that property when the user makes changes.

The NgModel directive serves that purpose as seen in this example:

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

If we prefer the “canonical” prefix form to the punctuation form, we can write

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

There’s a story behind this construction, a story that builds on the Property and Event Binding techniques we learned previously.

We could have achieved the same result as NgModel with separate bindings to the the <input> element's value property and input event.

<input [value]="currentHero.firstName" (input)="currentHero.firstName=$event.target.value" >

That’s cumbersome. Who can remember what element property to set and what event reports user changes? How do we extract the currently displayed text from the input box so we can update the data property? Who wants to look that up each time?

That ngModel directive hides these onerous details. It wraps the element’s value property, listens to the input event, and raises its own event with the changed text ready for us to consume.

<input [ngModel]="currentHero.firstName" (ngModelChange)="currentHero.firstName=$event">

That’s an improvement. It should be better.

We shouldn't have to mention the data property twice. Angular should be able to read the component’s data property and set it with a single declaration — which it can with the [( )] syntax:

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

Internally, Angular maps the term, ngModel, to an ngModel input property and an ngModelChange output property. That’s a specific example of a more general pattern in which it matches [(x)] to an x input property for Property Binding and an x-change output property for Event Binding.

We can write our own two-way binding directive that follows this pattern if we're ever in the mood to do so.

Is [(ngModel)] all we need? Is there ever a reason to fall back to its expanded form?

Well NgModel can only set the target property. What if we need to do something more or something different when the user changes the value?

Let's try something silly like forcing the input value to uppercase.

<input [ngModel]="currentHero.firstName" (ngModelChange)="setUpperCaseFirstName($event)">

Here are all variations in action, including the uppercase version:

NgModel variations

Built-in Directives

Earlier versions of Angular included over seventy built-in directives. The community contributed many more and individuals have created countless private directives for internal applications.

We don’t need many of those directives in Angular 2. Quite often we can achieve the same results with the more capable and expressive Angular 2 binding system. Why create a directive to handle a click when we can write a simple binding such as this?

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

We still benefit from directives that simplify complex tasks. Angular still ships with built-in directives; just not as many. We will write our own directives; just not as many.

In this segment we review some of the most frequently used built-in directives.

NgClass

We typically control how elements appear by adding and removing CSS classes dynamically. We can bind to NgClass to add or remove several classes simultaneously.

We prefer to use a Class Binding to add or remove a single class.

<!-- toggle the "special" class on/off with a property --> <div [class.special]="isSpecial">The class binding is special</div>

The NgClass directive may be the better choice when we want to add or remove many classes at the same time.

Our favorite way to apply NgClass is by binding it to a key:value control object. Each key of the object is a class name and its value is true if the class should be added, false if it should be removed.

Consider a component method such as setClasses that returns its approval of two class names:

setClasses() { return { saveable: this.canSave, // true modified: !this.isUnchanged, // false special: this.isSpecial, // true } }

Now add an NgClass property binding to call it like this

<div [ngClass]="setClasses()">This div is saveable and special</div>

NgStyle

We may set inline styles dynamically based on the state of the component. We bind to NgStyle to set many inline styles simultaneously.

We prefer to use a Style Binding to set a single style value.

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

The NgStyle directive may be the better choice when we want to set many inline styles at the same time.

We apply NgStyle by binding it to a key:value control object. Each key of the object is a style name and its value is whatever is appropriate for that style.

Consider a component method such as setStyles that returns an object defining three styles:

setStyles() { return { // CSS property names 'font-style': this.canSave ? 'italic' : 'normal', // italic 'font-weight': !this.isUnchanged ? 'bold' : 'normal', // normal 'font-size': this.isSpecial ? 'x-large': 'smaller', // larger } }

Now add an NgStyle property binding to call it like this

<div [ngStyle]="setStyles()"> This div is italic, normal weight, and x-large </div>

Alternatively, we can return an object with camelCase style property names with the same effects:

setStyles2() { return { // camelCase style properties work too fontStyle: this.canSave ? 'italic' : 'normal', // italic fontWeight: !this.isUnchanged ? 'bold' : 'normal', // normal fontSize: this.isSpecial ? 'x-large': 'smaller', // larger } }

NgIf

We can add an element sub-tree (an element and its children) to the DOM by binding an NgIf directive to a truthy expression.

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

The leading asterisk (*) in front of ngIf is a critical part of this syntax. See the section below on * and <template>.

Binding to a falsey expression removes the element sub-tree from the DOM.

<!-- not displayed because nullHero is falsey. `nullHero.firstName` never has a chance to fail --> <div *ngIf="nullHero">Hello, {{nullHero.firstName}}</div> <!-- Hero Detail is not in the DOM because isActive is false--> <hero-detail *ngIf="isActive"></hero-detail>

Visibility and NgIf are not the same

We can show and hide an element sub-tree (the element and its children) with a Class or a Style binding:

<!-- isSpecial is true --> <div [class.hidden]="!isSpecial">Show with class</div> <div [class.hidden]="isSpecial">Hide with class</div> <!-- HeroDetail is in the DOM but hidden --> <hero-detail [class.hidden]="isSpecial"></hero-detail> <div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div> <div [style.display]="isSpecial ? 'none' : 'block'">Hide with style</div>

Hiding a sub-tree is quite different from excluding a sub-tree with NgIf.

When we hide the element sub-tree, it remains in the DOM. Components in the sub-tree are preserved along with their state. Angular may continue to check for changes even to invisible properties. The sub-tree may tie up substantial memory and computing resources.

When NgIf is false, Angular physically removes the element sub-tree from the DOM. It destroys components in the sub-tree along with their state which may free up substantial resources resulting in better performance for the user.

The show/hide technique is probably fine for small element trees. We should be wary when hiding large trees; NgIf may be the safer choice. Always measure before leaping to conclusions.

NgSwitch

We bind to NgSwitch when we want to display one element tree (an element and its children) from a set of possible elment trees based on some condition. Angular only puts the selected element tree into the DOM.

Here’s an example:

<span [ngSwitch]="toeChoice"> <template [ngSwitchWhen]="'Eenie'">Eenie</template> <template [ngSwitchWhen]="'Meanie'">Meanie</template> <template [ngSwitchWhen]="'Miney'">Miney</template> <template [ngSwitchWhen]="'Moe'">Moe</template> <template ngSwitchDefault>Other</template> </span>

We bind the parent NgSwitch directive to an expression returning a “switch value”. The value is a string in this example but it can be a value of any type.

The parent NgSwitch directive controls a set of child<template> elements. Each <template> wraps a candidate subtree. A template is either pegged to a “match value” expression or marked as the default template.

At any particular moment, only one of these templates will be rendered

If the template’s “match value” equals the “switch value”, Angular adds the template’s sub-tree to the DOM. If no template is a match and there is a default template, Angular adds the default template’s sub-tree to the DOM. Angular removes and destroys the sub-tree’s of all other templates.

There are three collaborating directives at work here.

  1. ngSwitch - bound to an expression that returns the switch value.
  2. ngSwitchWhen - bound to an expression returning a match value.
  3. ngSwitchDefault - a marker attribute on the default template.

NgFor

NgFor is a “repeater” directive. It will be familiar if we’ve written repeaters for other view engines.

Our goal is to present a list of items. We define a block of HTML that defines how a single item should be displayed. We tell Angular to use that block as a template for rendering each item in the list.

Here is an example of NgFor applied to a simple <div>.

<div *ngFor="#hero of heroes">{{hero.fullName}}</div>

We can apply an NgFor to a component element as well as we do in this example:

<hero-detail *ngFor="#hero of heroes" [hero]="hero"></hero-detail>

The leading asterisk (*) in front of ngFor is a critical part of this syntax. See the section below on * and <template>.

The text assigned to *ngFor is the instruction that guides the repeater process.

NgFor Micro-syntax

The string assigned to *ngFor is not a template expression. It’s a little language of its own called a “micro-syntax” that Angular interprets. In this example it means:

Take each hero in the heroes array, store it in the local hero variable, and make it available to the templated HTML for each iteration.

Angular translates this instruction into a new set of elements and bindings. We’ll talk about this in the next section about templates.

In our two examples, the ngFor directive iterates over the heroes array returned by the parent component’s heroes property and stamps out instances of the element to which it is applied. Angular creates a fresh instance of the template for each hero in the array.

The (#) character before "hero" identifies a local template variable called hero.

We reference this variable within the template to access a hero’s properties as we’re doing in the interpolation or we can pass it in a binding to a component element as we're doing with hero-detail.

NgFor with index

The ngFor directive supports an optional index that increases from 0 to the length of the array for each iteration. We can capture that in another local template variable (i) and use it in our template too.

This next example stamps out rows that display like "1 - Hercules Son of Zeus":

<div *ngFor="#hero of heroes, #i=index">{{i + 1}} - {{hero.fullName}}</div>

* and <template>

When we reviewed the ngFor and ngIf built-in directives we called out an oddity of the syntax, the asterisk (*) that appears before the directive name.

This is a bit of “syntactic sugar” that makes it easier to read and write directives that modify HTML layout with the help of templates. NgFor, NgIf, and NgSwitch all add and remove element subtrees that are wrapped in <template> tags.

With the NgSwitch directive we always write the <template> tags explicitly as we saw above. There isn’t much choice; we define a different template for each switch choice and let the directive render the template that matches the switch value.

NgFor and NgIf only need one template, the template-to-repeat and the template-to-include respectively.

The (*) prefix syntax is a convenient way for developers to skip the <template> wrapper tags and focus directly on the HTML element to repeat or include. Angular sees the (*) and expands the HTML into the <template> tags for us.

Expanding *ngIf

We can do that ourselves if we wish. Instead of writing ...

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

… we can write:

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

Notice the (*) is gone and we have a Property Binding to the ngIf directive, applied in this case to the <template> rather than the application’s hero-detail component.

The [hero]="currentHero" binding remains on the child <hero-detail> element inside the template. Angular does that too.

Remember the brackets!

Don’t make the mistake of writing ngIf="currentHero"! That syntax assigns the string value, "currentHero", to ngIf. In JavaScript a non-empty string is a truthy value so ngIf would always be true and Angular will always display the hero-detail … even when there is no currentHero!

Expanding *ngFor

A similar transformation applies to *ngFor. We can "de-sugar" the syntax ourselves and go from ...

<hero-detail *ngFor="#hero of heroes" [hero]="hero"></hero-detail>

... to

<hero-detail template="ngFor #hero of heroes" [hero]="hero"></hero-detail>

... and from there to

<template ngFor #hero [ngForOf]="heroes"> <hero-detail [hero]="hero"></hero-detail> </template>

This is a bit more complex than NgIf because a repeater has more moving parts to configure. In this case, we have to remember the NgForOf directive that identifies the list. It should be clear why we prefer the *ngFor syntax to writing out this expanded HTML ourselves.

Local template variables

A local template variable is a vehicle for moving data across element lines.

We've seen the #hero local template variable several times in this chapter, most prominently when writing NgFor repeaters.

In the * and <templates> segment we learned how Angular expands an *ngFor on a component tag into a <template> that wraps the component.

<template ngFor #hero [ngForOf]="heroes"> <hero-detail [hero]="hero"></hero-detail> </template>

The (#) prefix character in front of "hero" means that we're defining a hero variable.

Some folks don't like the (#) character. The var- prefix is the “cannonical” alternative to "#". We could have declared our variable as var-hero.

We defined hero on the outer <template> element where it becomes the current hero item as Angular iterates through the list of heroes.

The hero variable appears again in the binding on the inner <hero-detail> component element. That's how each instance of the <hero-detail> gets its hero.

Referencing a local template variable

We can reference a local template variable on the same element, on a sibling element, or on any of its child elements.

Here are two other examples of creating and consuming a local template variable:

<!-- phone refers to the input element; pass its `value` to an event handler --> <input #phone placeholder="phone number"> <button (click)="callPhone(phone.value)">Call</button> <!-- fax refers to the input element; pass its `value` to an event handler --> <input var-fax placeholder="phone number"> <button (click)="callFax(fax.value)">Fax</button>

How it gets its value

The value assigned to the variable depends upon the context.

When a directive is present on the element, as it is in the earlier NgFor <hero-detail> component example, the directive sets the value. Accordingly, the NgFor directive sets the hero variable to a hero item from the heroes array.

When there is no directive present, as in phone and fax examples, Angular sets the variable to the element on which it was defined. We defined these variables on the input elements. We’re passing those input element objects across to the button elements where they become arguments to the call() methods in the event bindings.

NgForm and local template variables

Let's look at one final example, a Form, the poster child for local template variables.

The HTML for a form can be quite involved as we saw in the Forms chapter. The following is a simplified example — and it's not simple at all.

<form (ngSubmit)="onSubmit(theForm)" #theForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input class="form-control" required ngControl="firstName" [(ngModel)]="currentHero.firstName"> </div> <button type="submit" [disabled]="!theForm.form.valid">Submit</button> </form>

A local template variable, theForm, appears three times in this example, separated by a large amount of HTML.

<form (ngSubmit)="onSubmit(theForm)" #theForm="ngForm"> <!-- . . . --> <button type="submit" [disabled]="!theForm.form.valid">Submit</button> </form>

What is the value of theForm?

It would be the HTMLFormElement if Angular hadn't taken it over. It's actually ngForm, a reference to the Angular built-in NgForm directive that wraps the native HTMLFormElement and endows it with additional super powers such as the ability to track the validity of user input.

This explains how we can disable the submit button by checking theForm.form.valid and pass an object with rich information to the parent component's onSubmit method.

Input and Output Properties

We can only bind to target directive properties that are either inputs or outputs.

We're drawing a sharp distinction between a data binding target and a data binding source.

The target is to the left of the (=) in a binding expression. The source is on the right of the (=).

Every member of a source directive (typically a component) is automatically available for binding. We don't have to do anything special to access a component member in the quoted template expression to the right of the (=).

We have limited access to members of a target directive (typically a component). We can only bind to input and output properties of target components to the left of the (=).

Also remember that a component is a directive. In this section, we use the terms "directive" and "component" interchangeably.

In this chapter we’ve focused mainly on binding to component members within template expressions on the right side of the binding declaration. A member in that position is a binding “data source”. It's not a target for binding.

In the following example, iconUrl and onSave are members of the AppComponent referenced within template expressions to the right of the (=).

<img [src]="iconUrl"/> <button (click)="onSave()">Save</button>

They are neither inputs nor outputs of AppComponent. They are data sources for their bindings.

Now look at the HeroDetailComponent when it is the target of a binding.

<hero-detail [hero]="currentHero" (deleted)="onHeroDeleted($event)"> </hero-detail>

Both HeroDetail.hero and HeroDetail.deleted are on the left side of binding expressions. HeroDetail.hero is the target of a Property Binding. HeroDetail.deleted is the target of an Event Binding.

Data flow into the HeroDetail.hero target property from the template expression. Therefore HeroDetail.hero is an input property from the perspective of HeroDetail.

Events stream out of the HeroDetail.deleted target property and toward the receiver within the template expression. Therefore HeroDetail.deleted is an output property from the perspective of HeroDetail.

When we peek inside HeroDetailComponent we see that these properties are marked with decorators as input and output properties.

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

Alternatively, we can identify them in the inputs and outputs arrays of the directive metadata as seen in this example:

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

We can specify an input/output property with a decorator or in one the metadata arrays. Don't do both!

Aliasing input/output properties

Sometimes we want the public name of the property to be different from the internal name.

This is frequently the case with Attribute Directives. Directive consumers expect to bind to the name of the directive. For example, we expect to bind to the myClick event property of the MyClickDirective.

The directive name is often a poor choice for the the internal property name because it rarely describes what the property does. The corresponding MyClickDirective internal property is called clicks.

Fortunately, we can alias the internal name to meet the conventional needs of the directive's consumer. We alias in decorator syntax like this:

@Output('myClick') clicks = new EventEmitter<string>();

The equivalent aliasing with the outputs array requires a colon-delimited string with the internal property name on the left and the public name on the right:

@Directive({ outputs:['clicks:myClick'] })

Template Expression Operators

The template expression language employs a subset of JavaScript syntax supplemented with some special operators for specific scenarios. We'll cover two of them, "pipe" and "Elvis".

The Pipe Operator ( | )

The result of an expression may require some transformation before we’re ready to use it in a binding. For example, we may wish to display a number as a currency, force text to uppercase, or filter a list and sort it.

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 are easy to apply within template expressions using the pipe operator ( | ):

<!-- Force title to uppercase --> <div>{{ title | uppercase }}</div>

The pipe operator passes the result of an expression on the left to a pipe function on the right.

We can chain expressions through multiple pipes

<!-- Pipe chaining: force title to uppercase, then to lowercase --> <div>{{ title | uppercase | lowercase }}</div>

And we can configure them too:

<!-- pipe with configuration argument => "February 25, 1970" --> <div>Birthdate: {{currentHero?.birthdate | date:'longDate'}}</div>

The json pipe is particular helpful for debugging our bindings:

<div>{{currentHero | json}}</div> <!-- Output: { "firstName": "Hercules", "lastName": "Son of Zeus", "birthdate": "1970-02-25T08:00:00.000Z", "url": "http://www.imdb.com/title/tt0065832/", "rate": 325, "id": 1 } -->

The Elvis Operator ( ?. ) and null property paths

The Angular “Elvis” 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.

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

Let’s elaborate on the problem and this particular solution.

What happens when the following data bound title property is null?

The title is {{ title }}

The view still renders but the displayed value is blank; we see only "The title is" with nothing after it. That is reasonable behavior. At least the app doesn't crash.

Suppose the template expression involves a property path as in this next example where we’re displaying the firstName of a null hero.

The null hero's name is {{nullHero.firstName}}

JavaScript throws a null reference error and so does Angular:

TypeError: Cannot read property 'firstName' of null in [null]

Worse, the entire view disappears.

We could claim that this is reasonable behavior if we believed that the hero property must never be null. If it must never be null and yet it is null, we've made a programming error that should be caught and fixed. Throwing an exception is the right thing to do.

On the other hand, null values in the property path may be OK from time to time, especially when we know the data will arrive eventually.

While we wait for data, the view should render without complaint and the null property path should display as blank just as the title property does.

Unfortunately, our app crashes when the currentHero is null.

We could code around that problem with NgIf

<!--No hero, div not displayed, no error --> <div *ngIf="nullHero">The null hero's name is {{nullHero.firstName}}</div>

Or we could try to chain parts of the property path with &&, knowing that the expression bails out when it encounters the first null.

The null hero's name is {{nullHero && nullHero.firstName}}

These approaches have merit but they can be cumbersome, especially if the property path is long. Imagine guarding against a null somewhere in a long property path such as a.b.c.d.

The Angular “Elvis” operator ( ?. ) is a more fluent and convenient way to guard against nulls in property paths. The expression bails out when it hits the first null value. The display is blank but the app keeps rolling and there are no errors.

<!-- No hero, no problem! --> The null hero's name is {{nullHero?.firstName}}

It works perfectly with long property paths too:

a?.b?.c?.d

What Next?

We’ve completed our survey of Template Syntax. Time to put that knowledge to work as we write our own Components and Directives.

Next Step

Pipes