angular-docs-cn/public/docs/ts/latest/guide/template-syntax.jade

1278 lines
58 KiB
Plaintext
Raw Normal View History

include ../../../../_includes/_util-fns
:marked
2015-10-16 23:39:30 -04:00
# 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.
2015-10-16 23:39:30 -04:00
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.
2015-10-16 23:39:30 -04:00
Lets find out what it takes to write a Template for our view.
2015-10-16 23:39:30 -04:00
Well cover these basic elements of Template Syntax
2015-10-16 23:39:30 -04:00
>[HTML](#html)
2015-10-16 23:39:30 -04:00
>[Interpolation](#interpolation)
2015-10-16 23:39:30 -04:00
>[Template expressions](#template-expressions)
2015-10-16 23:39:30 -04:00
>[Binding syntax](#binding-syntax)
2015-10-16 23:39:30 -04:00
>[Property Binding](#property-binding)
2015-10-16 23:39:30 -04:00
>[Attribute, Class and Style Bindings](#other-bindings)
2015-10-16 23:39:30 -04:00
>[Event Binding](#event-binding)
2015-10-16 23:39:30 -04:00
>[Two-way data binding with `NgModel`](#ng-model)
2015-10-16 23:39:30 -04:00
>[Built-in Directives](#directives)
2015-10-16 23:39:30 -04:00
>[* and <template>](#star-template)
2015-10-19 23:14:51 -04:00
>[Local template variables](#local-vars)
2015-10-16 23:39:30 -04:00
>[Input and Output Properties](#inputs-outputs)
2015-10-16 23:39:30 -04:00
>[Template Expression Operators](#expression-ops)
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
## HTML
HTML is the language of the Angular template. Our “[QuickStart](./quickstart.html)” application had a template that was pure HTML
code-example(format="" language="html" escape="html").
<h3>My First Angular Application</h3>
:marked
2015-10-16 23:39:30 -04:00
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).
2015-10-16 23:39:30 -04:00
Some legal HTML doesnt 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.
2015-10-16 23:39:30 -04:00
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.
2015-10-16 23:39:30 -04:00
Lets turn to the first form of data binding - interpolation - to see how much richer Template HTML can be.
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
## Interpolation
We met the double-curly braces of interpolation, `{{` and `}}`, early in our Angular education.
2015-10-16 23:39:30 -04:00
code-example(format="" language="html" escape="html").
<p>My current hero is {{currentHero.firstName}}</p>
:marked
2015-10-16 23:39:30 -04:00
We use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments.
code-example(format="" language="html" escape="html").
<h3>
{{title}}
2015-10-16 23:39:30 -04:00
<img src="{{heroImageUrl}}" height=30>
</h3>
:marked
The material between the braces is often the name of a component property. Angular replaces that name with the
2015-10-16 23:39:30 -04:00
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**
2015-10-16 23:39:30 -04:00
and then **converts to a string**. The following interpolation illustrates the point by adding the two numbers within braces:
code-example(format="" language="html" escape="html").
<!-- "The sum of 1 + 1 is 2" -->
<h1>The sum of 1 + 1 is {{1 + 1}}</h1>
:marked
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**.
2015-10-16 23:39:30 -04:00
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
2015-10-16 23:39:30 -04:00
[Property Binding](#property-binding) as we explain below. The implications and consequences can be profound.
But before we explore that assertion, well take a closer look at template expressions.
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
## Template Expressions
We saw a template expression within the interpolation braces.
Well see template expressions again in [Property Bindings](#property-binding) (`[property]="expression"`) and
2015-10-16 23:39:30 -04:00
[Event Bindings](#event-binding) (`(event)="expression"`).
2015-10-16 23:39:30 -04:00
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:
* Assignment is prohibited except in [Event Bindings](#event-binding).
* The `new` operator is prohibited.
* The bit-wise operators, `|` and `&`, are not supported.
* Increment and decrement operators, `++` and `--`, arent supported.
* [Template expression operators](#expression-operators), such as `|` and `?.`, add new meaning.
Perhaps more surprising, we cannot refer to anything in the global namespace.
We cant refer to `window` or `document`. We cant call `console.log`.
2015-10-16 23:39:30 -04:00
We are restricted to referencing members of the expression context.
2015-10-16 23:39:30 -04:00
The **expression context** is typically the **component instance** supporting a particular template instance.
.l-sub-section
:marked
We speak of component and template ***instances***. Angular creates multiple concrete instances from a component class and its template.
2015-10-16 23:39:30 -04:00
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. Theres a separate, independent expression context for each item in that list as well.
:marked
When we see `title` wrapped in double-curly braces,
2015-10-16 23:39:30 -04:00
we know that it is a property of a parent component.
When we see `[disabled]="isUnchanged"` or `(click)="onCancel()”`,
2015-10-16 23:39:30 -04:00
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](#local-vars) is one such supplemental context object;
well discuss that option below.
Another is the **`$event`** variable that contains information about an event raised on an element;
2015-10-16 23:39:30 -04:00
well talk about that when we consider [Event Bindings](#event-binding).
.l-sub-section
:marked
2015-10-16 23:39:30 -04:00
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.
:marked
2015-10-16 23:39:30 -04:00
Now that we have a feel for template expressions, were ready to learn about the varieties of data binding syntax beyond Interpolation.
2015-10-16 23:39:30 -04:00
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
<a id="binding-syntax"></a>
## 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.
2015-10-16 23:39:30 -04:00
We simply declare bindings between the HTML and the data properties and let the framework do the work.
2015-10-16 23:39:30 -04:00
Angular provides many kinds of data binding and well discuss each of them in this chapter.
First we'll take a high level view of Angular data binding and its syntax.
2015-10-16 23:39:30 -04:00
We can group all bindings into three categories by the direction in which data flows. Each category has its distinctive syntax:
table
tr
th Data Direction
th Syntax
th Binding Type
tr
td One way<br>from data source<br>to view target
td
code-example(format="" ).
{{expression}}
[target] = "expression"
bind-target = "expression"
td.
2015-10-16 23:39:30 -04:00
Interpolation<br>
Property<br>
Attribute<br>
Class<br>
Style
tr
td One way<br>from view target<br>to data source
td
code-example(format="" ).
(target) = "expression"
on-target = "expression"
td Event
tr
td Two way
td
code-example(format="" ).
[(target)] = "expression"
bindon-target = "expression"
td Two-way
:marked
2015-10-16 23:39:30 -04:00
**Template expressions must be surrounded in quotes**
except for interpolation expressions which must not be quoted.
2015-10-16 23:39:30 -04:00
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.
2015-10-16 23:39:30 -04:00
### A New Mental Model
2015-10-16 23:39:30 -04:00
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 its also significantly different than the HTML were used to.
2015-10-16 23:39:30 -04:00
We really need a new mental model.
2015-10-16 23:39:30 -04:00
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">
<img src="./image/hero.png">
<button disabled>Save</button>
</div>
```
We still create a structure and initialize attribute values this way in Angular templates.
2015-10-16 23:39:30 -04:00
Then we learn to create new elements with Components and drop them into our HTML as if they were native HTML elements
```
<div class="special">
<hero-detail></hero-detail>
</div>
```
Thats “HTML Plus”.
Now we are learning about data binding. At first glance it appears that we are setting attributes,
as when we bind button `disabled` to the components `isUnchanged` property:
2015-10-16 23:39:30 -04:00
```
<button [disabled]="isUnchanged">Save</button>
```
Well get to that peculiar bracket notation in a moment. Looking beyond it,
2015-10-16 23:39:30 -04:00
our intuition tells us that were binding to the button's `disabled` attribute and setting
it to the current value of the components `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.
.l-sub-section
:marked
### 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).**
* A few HTML attributes have 1:1 mapping to properties. `id` is one example.
* Some HTML attributes don't have corresponding properties. `colspan` is one example.
* Some DOM properties don't have corresponding attributes. `textContent` is one example.
* Many HTML attributes appear to map to properties ... but not the way we think!
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.**
:marked
2015-10-16 23:39:30 -04:00
This is so important, well say it again.
2015-10-16 23:39:30 -04:00
**Template binding works with *properties* and *events*, not *attributes*.**
2015-10-16 23:39:30 -04:00
.callout.is-helpful
header A world without attributes
:marked
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.
2015-10-16 23:39:30 -04:00
Attributes effectively disappear.
:marked
With this model firmly in mind, we are ready to discuss the variety of target properties to which we may bind.
2015-10-16 23:39:30 -04:00
### 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.
2015-10-16 23:39:30 -04:00
The following table summarizes:
<div width="90%">
table
tr
th Binding Type
th Target
th Examples
tr
td Property
td.
2015-10-16 23:39:30 -04:00
Element&nbsp;Property<br>
Component&nbsp;Property<br>
Directive&nbsp;property
td
code-example(format="", language="html").
&lt;img [src] = "heroImageUrl"&gt;
&lt;hero-detail [hero]="currentHero"&gt;
&lt;div [ng-class] = "{selected: isSelected}"&gt;
tr
td Event
td.
2015-10-16 23:39:30 -04:00
Element&nbsp;Event<br>
Component&nbsp;Event<br>
Directive&nbsp;Event
td
code-example(format="", language="html").
&lt;button (click) = "onSave()"&gt;
&lt;hero-detail (deleted)="onDeleted()"&gt;
&lt;input (ng-model-change) = "firstName = $event"&gt;
tr
td Two-way
td.
2015-10-16 23:39:30 -04:00
Directive&nbsp;Event
Property
td
code-example(format="", language="html").
&lt;input [(ng-model)] = "firstName"&gt;
tr
td Attribute
td.
2015-10-16 23:39:30 -04:00
Attribute
(the&nbsp;exception)
td
code-example(format="", language="html").
&lt;button [attr.aria-label] = "actionName"&gt;
tr
td Class
td.
2015-10-16 23:39:30 -04:00
<code>class</code> Property
td
code-example(format="", language="html").
&lt;div [class.special] = "isSpecial"&gt;
2015-10-16 23:39:30 -04:00
tr
td Style
td.
2015-10-16 23:39:30 -04:00
<code>style</code> Property
td
code-example(format="", language="html").
&lt;button [style.color] = "isSpecial ?'red' : 'green'"&gt;
</div>
:marked
2015-10-16 23:39:30 -04:00
### Spelling target names
The target name whether between punctuation or after a prefix -
should be spelled with **lowercase**. Although we can spell it in mixed-case,
2015-10-16 23:39:30 -04:00
Angular sees it only after it has been forced to lowercase.
Thats a problem when we need to reference a property with a mixed-case name.
HTML elements have many mixed-case properties: `innerHTML`, `textContent`, `className` to name a few.
Our custom elements (e.g., `<hero-detail>`) may have mixed-case property names
2015-10-16 23:39:30 -04:00
(`HeroDetailComponent.isActive`).
2015-10-16 23:39:30 -04:00
Well be tempted to write bindings that target such properties in mixed-case:
```
<!-- BAD: No Mixed Case -->
<label [textContent] = "title">
<hero-detail [isActive] = "isActive">
```
Try it and the entire display goes blank. A debugger reveals the error:
code-example(format="", language="html").
Template parse errors:
Can't bind to 'textcontent' since it isn't a known native property in ...
:marked
2015-10-16 23:39:30 -04:00
Notice that it forced mixed-case ""text**C**ontent" to lowercase "text**c**ontent".
The solution is to write the target property name in “**lower kebab case**”,
2015-10-16 23:39:30 -04:00
with a dash before each uppercase letter. We can correct the example as follows:
```
<!-- Lower Kebab Case -->
2015-10-16 23:39:30 -04:00
<label [text-content] = "title">
<hero-detail [is-active] = "isActive">
```
.l-sub-section
:marked
According to this rule, we should write `[inner-h-t-m-l]` to access the elements `innerHTML` property.
2015-10-16 23:39:30 -04:00
Fortunately, the Angular template parser recognizes `inner-html` as an acceptable alias for `innerHTML`.
:marked
2015-10-16 23:39:30 -04:00
Lets descend from the architectural clouds and look at each of these binding types in concrete detail.
2015-10-16 23:39:30 -04:00
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
## 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
2015-10-16 23:39:30 -04:00
we bind the source property of an image element to the components `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 [ng-class]="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 components 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 elements `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 its the name of an attribute. No. Its 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
2015-10-16 23:39:30 -04:00
as it is in the following example:
```
<div [ng-class]="special">NgClass is special</div>
```
.l-sub-section
:marked
Technically, Angular is matching the name to a directive [input](#inputs-outputs),
one of the property names listed in the directives `inputs` array or a property decorated with `@Input()`.
2015-10-16 23:39:30 -04:00
Such inputs map to the directives own properties.
:marked
2015-10-16 23:39:30 -04:00
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 cant assign a value to anything in a Property Binding expression nor use the increment and decorator operators.
2015-10-16 23:39:30 -04:00
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.
2015-10-16 23:39:30 -04:00
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.
2015-10-16 23:39:30 -04:00
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`.
2015-10-16 23:39:30 -04:00
The `hero` property of the `HeroDetail` component expects a `Hero` object which is exactly what were sending in the Property Binding:
```
<hero-detail [hero]="selectedHero"></hero-detail>
```
This is good news for the Angular developer.
2015-10-16 23:39:30 -04:00
If `hero` were an attribute we could not set it to a `Hero` object.
```
<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.
2015-10-16 23:39:30 -04:00
Thats 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
2015-10-16 23:39:30 -04:00
set the element property directly with a value of the appropriate type.
2015-10-16 23:39:30 -04:00
### Property Binding or Interpolation?
We often have a choice between Interpolation and Property Binding. The following binding pairs do the same thing
code-example(language="html").
&lt;img src="{{heroImageUrl}}"&lt/>
&lt;img [src]="'' + heroImageUrl"&lt/>
2015-10-16 23:39:30 -04:00
&lt;h3>The title is {{title}}&lt/h3>
&lt;h3>[text-content]="'The title is '+title">&lt/h3>
:marked
Interpolation is actually a convenient alternative for Property Binding in many cases.
In fact, Angular translates those Interpolations into the corresponding Property Bindings
2015-10-16 23:39:30 -04:00
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
2015-10-16 23:39:30 -04:00
both conforms to the rules and feels most natural for the task at hand.
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
<a id="other-bindings"></a>
## Attribute, Class, and Style Bindings
The template syntax provides specialized one-way bindings for scenarios less well suited to Property Binding.
2015-10-16 23:39:30 -04:00
### Attribute Binding
We can set the value of an attribute directly with an **Attribute Binding**.
.l-sub-section
:marked
2015-10-16 23:39:30 -04:00
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.
:marked
2015-10-16 23:39:30 -04:00
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?
2015-10-16 23:39:30 -04:00
**We must use Attribute Binding when there is no element property to bind.**
2015-10-16 23:39:30 -04:00
Consider the [aria](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA),
[svg](https://developer.mozilla.org/en-US/docs/Web/SVG), and
table span attributes. They are pure attributes.
They do not correspond to element properties and they do not set element properties.
2015-10-16 23:39:30 -04:00
There are no property targets to bind to.
2015-10-16 23:39:30 -04:00
We become painfull aware of this fact when we try to write something like this:
code-example(language="html").
&lt;tr>&lt;td colspan="{{1+1}}">Three-Four&lt;/td>&lt;/tr>
:marked
2015-10-16 23:39:30 -04:00
… and get the error:
code-example(format="", language="html").
Template parse errors:
2015-10-16 23:39:30 -04:00
Can't bind to 'colspan' since it isn't a known native property
:marked
As the message says, the `<td>` element does not have a `colspan` property.
2015-10-16 23:39:30 -04:00
It has the `colspan` attribute but Interpolation and Property Binding set properties, not attributes.
2015-10-16 23:39:30 -04:00
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`**
2015-10-16 23:39:30 -04:00
followed by the name of the attribute, `[attr.attribute-name]`, and then set it with an expression that resolves to a string.
2015-10-16 23:39:30 -04:00
Here's how we could use it to set the `colspan` attribute for a row in a table.
```
<table border=1>
<tr><td>One</td><td>Two</td></tr>
2015-10-16 23:39:30 -04:00
<!-- ERROR: There is no `colspan` property we can bind to.
<tr><td [colspan]="1 + 1">Three-Four</td></tr>
-->
2015-10-16 23:39:30 -04:00
<!-- expression calculates colspan=2 -->
<tr><td [attr.colspan]="1 + 1">Five-Six</td></tr>
</table>
```
Here's how the table renders:
<table border="1px">
<tr><td>One</td><td>Two</td></tr>
<tr><td colspan="2">Five-Six</td></tr>
</table>
One of the primary use cases for the Attribute Binding
2015-10-16 23:39:30 -04:00
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 elements `class` attribute with the **Class Binding**.
2015-10-16 23:39:30 -04:00
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]`.
2015-10-16 23:39:30 -04:00
Angular adds the class name when the template expression evaluates to something truthy and removes the class name when the expression is falsey.
```
<style>.special { font-weight:bold; }</style>
<div class="special">The class is special</div>
<!-- toggle the "special" class on and off -->
<div [class.special]="isSpecial">The class binding is special</div>
2015-10-16 23:39:30 -04:00
<div class="special" [class.special]="!isSpecial">This one is not so special</div>
```
.l-sub-section
:marked
While this is a fine way to toggle a single class name,
2015-10-16 23:39:30 -04:00
we generally prefer the [NgClass directive](#ng-class) for managing multiple class names at the same time.
:marked
2015-10-16 23:39:30 -04:00
### Style Binding
2015-10-16 23:39:30 -04:00
We can set inline styles with a **Style Binding**.
2015-10-16 23:39:30 -04:00
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]`.
2015-10-16 23:39:30 -04:00
```
<button [style.color]="isSpecial?'red':'green'">Red</button>
<button [style.background-color]="canSave?'cyan':'grey'" >Save</button>
```
Some Style Binding styles have unit extension. Here we conditionally set the `font-size` in “em” and “%” units .
```
<button [style.font-size.em]="isSpecial ? 3 : 1" >Big</button>
<button [style.font-size.%]="!isSpecial ? 150 : 50" >Small</button>
```
.l-sub-section
:marked
While this is a fine way to set a single style,
2015-10-16 23:39:30 -04:00
we generally prefer the [NgStyle directive](#ng-style) for when setting several inline styles at the same time.
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
## Event Binding
The bindings weve met so far flow data in one direction *from the component to an element*.
Users dont just stare at the screen. They enter text into a textbox. They pick items from a list.
They click buttons. Such user actions may result in a flow of data in the opposite direction,
2015-10-16 23:39:30 -04:00
***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.
2015-10-16 23:39:30 -04:00
We declare our interest in user actions through Angular Event Binding.
2015-10-16 23:39:30 -04:00
The following Event Binding listens for the buttons 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 buttons click event.
```
<button (click)="onSave()">Save</button>
```
Some developers prefer the `on-` prefix alternative, known as the “canonical form”:
```
<button on-click="onSave()">Save</button>
```
Element events may be the more common targets, but Angular looks first to see if the name matches an event property
2015-10-16 23:39:30 -04:00
of a known directive as it does in the following example:
```
<input (ng-model-change)="firstName = $event">
```
.l-sub-section
:marked
2015-10-16 23:39:30 -04:00
`ng-model-change` translates to the `ngModelChange` property of the `NgModel` directive.
Technically, Angular is matching the target binding name to a directive [output](#inputs-outputs) property,
one of the property names listed in the directives `outputs` array or a property decorated with `@Output`.
2015-10-16 23:39:30 -04:00
Such outputs map to the directives own internal properties as in this example where
`ngModelChange` maps to the directive's hidden `update` property.
2015-10-16 23:39:30 -04:00
These details are not something we generally need or want to know.
:marked
2015-10-16 23:39:30 -04:00
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.
2015-10-16 23:39:30 -04:00
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.
2015-10-16 23:39:30 -04:00
The binding conveys information about the event including data values through
an **event object named `$event`**.
2015-10-16 23:39:30 -04:00
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
2015-10-16 23:39:30 -04:00
[DOM event object]( https://developer.mozilla.org/en-US/docs/Web/Events) with properties such as `target` and `target.value`.
2015-10-16 23:39:30 -04:00
Consider this example:
```
<input [value]="currentHero?.firstName"
(input)="currentHero.firstName=$event.target.value">
```
Were binding the textbox `value` to a `firstName` property and were listening for changes by binding to the textboxs `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`
2015-10-16 23:39:30 -04:00
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 `onDeleted()` method that looks like this:
```
deleted = new EventEmitter();
onDelete() {
this.deleted.next(this.hero);
}
```
It sends a `Hero` object when it raises its `deleted` event. the `$event` will be that hero.
Imagine a parent component that binds to the `HeroDetailComponent.deleted` event with its own `onDeleted` method
2015-10-16 23:39:30 -04:00
```
<hero-detail [hero]="currentHero" (deleted)="onDeleted($event)"></hero-detail>
```
Our binding passes the *hero-to-delete* via the `$hero` variable
2015-10-16 23:39:30 -04:00
to the parent `onDeleted()` method
which presumably knows what is necessary to delete that hero.
2015-10-16 23:39:30 -04:00
Evaluation of an Event Binding template expression may have side-effects.
The expression could update the model, trigger other changes that percolate through the system, changes that
are ultimately displayed in this view and other views.
2015-10-16 23:39:30 -04:00
The event processing may result in queries and saves to a remote server. Unlike with Property Bindings,
such side-effects are just fine.
2015-10-16 23:39:30 -04:00
### 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>
```
2015-10-16 23:39:30 -04:00
Many DOM events, both [native](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Overview_of_Events_and_Handlers ) and [custom](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events ), “bubble” events up their ancestor tree of DOM elements until an event handler along the way prevents further propagation.
2015-10-16 23:39:30 -04:00
.l-sub-section
:marked
2015-10-16 23:39:30 -04:00
`EventEmitter` events dont bubble.
:marked
The result of an Event Binding expression determines if
[event propagation](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Examples#Example_5:_Event_Propagation)
continues or stops with the current element.
2015-10-16 23:39:30 -04:00
Propagation stops if the expression returns a falsey value (such as `void`):
```
<button (click)="onSave()">On Save</button>
```
Propagation continues if the expression returns a truthy value:
```
<button (click)="onSave() || true">On Save w/ propagation</button>
```
2015-10-16 23:39:30 -04:00
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
<a name="ng-model"></a>
## 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.
2015-10-16 23:39:30 -04:00
The `NgModel` directive serves that purpose as seen in this example:
```
<input [(ng-model)] = "currentHero.firstName">
```
If we prefer the “canonical” prefix form to the punctuation form, we can write
```
<input bindon-ng-model= "currentHero.firstName">
```
Theres a story behind this construction, a story that builds on the Property and Event Binding techniques we learned previously.
2015-10-16 23:39:30 -04:00
We could have achieved the same result as `NgModel` with the following, separate Property and Event Bindings:
```
<input [value]="currentHero.firstName"
(input)="currentHero.firstName=$event.target.value">
```
Thats cumbersome to say the least. It requires that we remember what element property to set, what event tells us about user changes, and how to extract the currently displayed text from the textbox so we can update the data property.
2015-10-16 23:39:30 -04:00
A directive can hide these onerous details. Such a directive can wrap the elements `value` property, listen to the `input` event, and raise its own event with the changed text ready to consume. We wouldnt have to remember anything but the directive name.
2015-10-16 23:39:30 -04:00
That directive is `ng-model`. We can re-write the previous example like this:
```
<input
2015-10-16 23:39:30 -04:00
[ng-model]="currentHero.firstName"
(ng-model-change)="currentHero.firstName=$event">
```
Thats an improvement but we can do better yet. Were telling `NgModel` about the data property twice and if `NgModel` knows how to read the components data property it should know how to set it.
2015-10-16 23:39:30 -04:00
Angular offers a syntax - `[(…)]` - that combines the notation for Property Binding and Event Binding just as it combines their purpose in a single binding declaration:
```
<input [(ng-model)] = "currentHero.firstName">
```
2015-10-16 23:39:30 -04:00
.l-sub-section
:marked
Internally, Angular maps the term, `ng-model`, to an `ng-model` input property and an
`ng-model-change` output property.
Thats a specific example of a more general pattern in which it matches `[(x)]` to an `x` input property
2015-10-16 23:39:30 -04:00
for Property Binding and an `x-change` output property for Event Binding.
2015-10-16 23:39:30 -04:00
We can write our own two-way binding directive that follows this pattern if we're ever in the mood to do so.
:marked
2015-10-16 23:39:30 -04:00
*Before* we can use `NgModel`, we must import it via the `FORM_DIRECTIVES` directives array
```
import {FORM_DIRECTIVES} from angular2/angular2`
2015-10-16 23:39:30 -04:00
```
and include that array among the list of directives used by the components template (`directives: [FORM_DIRECTIVES]`).
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
<a name="directives"></a>
## Built-in Directives
2015-10-16 23:39:30 -04:00
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 dont 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.
2015-10-16 23:39:30 -04:00
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.
We will write our own directives; just not as many.
2015-10-16 23:39:30 -04:00
Angular still ships with built-in directives; just not as many.
Well review some of the most frequently used built-in directives in this segment.
2015-10-16 23:39:30 -04:00
We can import them all at once with the `CORE_DIRECTIVES` directive array
```
import {CORE_DIRECTIVES} from angular2/angular2;
```
Remember to add `CORE_DIRECTIVES` to the components `directives` metadata array as shown here:
2015-10-16 23:39:30 -04:00
```
directives: [CORE_DIRECTIVES, FORM_DIRECTIVES, HeroDetailComponent]
```
<a id="ng-class"></a>
2015-10-16 23:39:30 -04:00
### NgClass
We typically control how elements appear
by adding and removing CSS classes dynamically.
2015-10-16 23:39:30 -04:00
We bind to `NgClass` to add or remove several classes simultaneously.
We can use a [Class Binding](#class-binding) to add or remove a *single* class.
2015-10-16 23:39:30 -04:00
```
<div [ng-class]="special">NgClass 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.
2015-10-16 23:39:30 -04:00
Consider a component method such as this:
```
setClasses() {
return {
saveable: this.canSave, // true
modified: !this.isUnchanged, // false
special: this.isSpecial, // true
}
}
```
We can add an `NgClass` Property Binding like this
```
<div [ng-class]="setClasses()">This div is saveable and special</div>
```
2015-10-16 23:39:30 -04:00
<a id="ng-style"></a>
### NgStyle
We may set inline styles dynamically based on the state of the component.
2015-10-16 23:39:30 -04:00
We bind to `NgStyle` to set many inline styles simultaneously.
We can use a [Style Binding](#style-binding) to set a *single* style value.
2015-10-16 23:39:30 -04:00
```
<div [style.font-size]="isSpecial ? 'larger' : 'smaller'" >This div is larger</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.
2015-10-16 23:39:30 -04:00
Consider a component method such as this:
```
setStyles() {
return {
'font-style': this.canSave ? 'italic' : 'normal', // italic
'font-weight': !this.isUnchanged ? 'bold' : 'normal', // normal
'font-size': this.isSpecial ? 'larger' : 'smaller', // larger
}
}
```
We can add an `NgStyle` Property Binding like this
```
<div [ng-style]="setStyles()">This div is italic, normal weight, and larger</div>
```
2015-10-16 23:39:30 -04:00
<a id="ng-if"></a>
### 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; binding to a falsey expression removes the element sub-tree from the DOM.
```
<div *ng-if="currentHero">Add {{currentHero.firstName}}</div>
<div *ng-if="nullHero">Remove {{nullHero.firstName}}</div>
2015-10-16 23:39:30 -04:00
<div>Hero Detail removed from DOM because isActive is false</div>
<hero-detail *ng-if="isActive" [hero]="currentHero"></hero-detail>
```
.alert.is-critical
:marked
The leading asterisk (`*`) in front of `ng-if` is a critical part of this syntax.
2015-10-16 23:39:30 -04:00
See the section below on [* and &lt;template>](#star-template).
:marked
2015-10-16 23:39:30 -04:00
#### Visibility and NgIf are not the same
We can show and hide an element sub-tree (the element and its children) with a [Class](#class-binding) or a [Style](#style-binding) binding:
```
<style>.hidden {display: none}</style>
<!-- isSpecial is true -->
<div [class.hidden]="!isSpecial">Show with class</div>
<div [class.hidden]="isSpecial">Hide with class</div>
<hero-detail [class.hidden]="isSpecial" [hero]="currentHero"></hero-detail>
2015-10-16 23:39:30 -04:00
<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.
2015-10-16 23:39:30 -04:00
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.
2015-10-16 23:39:30 -04:00
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.
2015-10-16 23:39:30 -04:00
<a id="ng-switch"></a>
### NgSwitch
2015-10-16 23:39:30 -04:00
We bind to `NgSwitch` when we want to insert one element sub-tree (an element and its children) into the DOM from a set of alternative sub-trees.
2015-10-16 23:39:30 -04:00
Heres an example:
```
<div class="toe">You picked
2015-10-16 23:39:30 -04:00
<span [ng-switch]="toeChoice(toePicker)">
<template [ng-switch-when]="'Eenie'">Eenie</template>
<template [ng-switch-when]="'Meanie'">Meanie</template>
<template [ng-switch-when]="'Miney'">Miney</template>
<template [ng-switch-when]="'Moe'">Moe</template>
<template ng-switch-default>Other</template>
</span>
</div>
```
We bind the parent `NgSwitch` element to an expression returning a “switch value”. The value is a string in this example but it can be a value of any type.
2015-10-16 23:39:30 -04:00
The parent `NgSwitch` element 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.
2015-10-16 23:39:30 -04:00
**At any particular moment, only one of these templates will be rendered**
2015-10-16 23:39:30 -04:00
If the templates “match value” equals the “switch value”, Angular adds the templates sub-tree to the DOM. If no template is a match and there is a default template, Angular adds the default templates sub-tree to the DOM. Angular removes and destroys the sub-trees of all other templates.
2015-10-16 23:39:30 -04:00
There are three related directives at work here.
1. `ng-switch` - bound to an expression that returns the switch value.
1. `ng-switch-when` - bound to an expression returning a match value.
1. `ng-switch-default` - a marker attribute on the default template.
<a id="ng-for"></a>
### NgFor
To display items of a list, we create new instances of a master element sub-tree (an element and its children) for each item.
2015-10-16 23:39:30 -04:00
`NgFor` is a “repeater” directive which may be familiar to us if weve written templates before for other view engines.
Here is an example of the most compact `NgFor` syntax, applied to a simple `<div>` template.
2015-10-16 23:39:30 -04:00
```
<div *ng-for="#hero of heroes">{{hero.fullName}}</div>
```
.alert.is-critical
:marked
2015-10-16 23:39:30 -04:00
The leading asterisk (`*`) in front of `ng-for` is a critical part of this syntax. See the section below on [* and &lt;template>](#star-template).
:marked
2015-10-16 23:39:30 -04:00
The `ng-for` directive iterates over the `heroes` array returned by the parent components `heroes` property and stamps out instances of the `<div>` template.
2015-10-16 23:39:30 -04:00
The quoted text assigned to `ng-for` means “*take each hero in the `heroes` array, store it in the local `hero` variable, and make it available to the template instance*”. Angular creates one fresh instance of the `<div>` template for each hero in the array.
2015-10-16 23:39:30 -04:00
The `#` prefix before "hero" identifies the `hero` as a [local template variable](#local-vars). We can reference this variable within the template to access a heros properties as were doing in the interpolation.
2015-10-16 23:39:30 -04:00
The `ng-for` directive also provides 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.
2015-10-16 23:39:30 -04:00
This next example stamps out rows like "1 - Hercules Son of Zeus":
code-example(format="" language="html").
&lt;div *ng-for="#hero of heroes", #i=index">{{i+1}} - {{hero.fullName}}&lt;/div>
:marked
We can apply an `ng-for` repeater to Components as well,
2015-10-16 23:39:30 -04:00
as we do in this following example with the `LittleHeroComponent`:
code-example(format="" language="html").
&lt;little-hero *ng-for="#hero of heroes" [hero]="hero">&lt;/little-hero>
:marked
2015-10-16 23:39:30 -04:00
The template in this case is defined by `LittleHeroComponent` itself. Angular creates a new instance of this component for each hero in the array and assigns the `hero` local *variable* to the `hero`* [input property](#inputs-outputs)* of each instance.
2015-10-16 23:39:30 -04:00
#### Micro-syntax
The string assigned to `*ng-for` is not a [template expression](#template-expressions). Its a little language of its own called a “micro-syntax” that Angular interprets and transforms into a set of bindings, each of a kind weve seen before.
2015-10-16 23:39:30 -04:00
Well talk about this in the next section about templates.
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
<a name="star-template"></a>
<a name="structural-directive"></a>
## * and &lt;template>
When we reviewed the `ng-for` and `ng-if` built-in directives we called out an oddity of the syntax, the asterisk (*) that appears before the directive name.
2015-10-16 23:39:30 -04:00
This is a bit of “**syntactic sugar**” that makes it easier to read and write certain HTML layout patterns.
implemented by **Structural Directives**.
The `ng-for`,`ng-if`, and `ng-switch` directives are in this the relatively rare
category of Structural Directive.
Instead of defining and controlling a view like
a **Component Directive**, or modifying the appearance and behavior of an element
like an **Attribute Directive**,
2015-10-16 23:39:30 -04:00
the **Structural Directive** manipulates the layout by adding
and removing entire element sub-trees.
Thats what `ng-for`, `ng-if`, and `ng-switch` do.
2015-10-16 23:39:30 -04:00
They add and remove element subtrees that are wrapped in `<template>` tags.
The `ng-switch` directive always makes explicit use of the `<template>` tags as we saw [above](#ng-switch).
2015-10-16 23:39:30 -04:00
There isnt much choice; we define a different template for each switch choice
and let the directive render the one template that matches the switch value.
But `ng-for` and `ng-if` only care about a single 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
2015-10-16 23:39:30 -04:00
focus directly on the HTML element that we want to repeat or include.
2015-10-16 23:39:30 -04:00
In reality, Angular sees the (*) and expands the HTML into the `<template>` form
that we wrote for `ng-switch`. We can do this same thing ourselves with `ng-if`.
2015-10-16 23:39:30 -04:00
Instead of writing ...
```
<hero-detail *ng-if="isActive" [hero]="currentHero"></hero-detail>
```
… we can write:
```
<template [ng-if]="isActive">
<hero-detail [hero]="currentHero"></hero-detail>
</template>
```
Notice the (*) is gone and we have a [Property Binding](#property-binding) to the `ng-if`
directive, applied in this case to the `<template>` rather than
2015-10-16 23:39:30 -04:00
the applications `hero-detail` component.
We put the `[hero]=”currentHero”` binding on the child `<hero-detail>`
2015-10-16 23:39:30 -04:00
element inside the template. Angular does that too.
2015-10-16 23:39:30 -04:00
.callout.is-critical
header Remember the brackets!
:marked
Dont make the mistake of writing `ng-if="isActive"`!
That syntax assigns the "isActive" string to the `ng-if` directive.
2015-10-16 23:39:30 -04:00
In JavaScript a non-empty string is a truthy value so `ng-if` is always
set `true` and always displays `hero-detail`
2015-10-16 23:39:30 -04:00
… even when the parent components `isActive` property returns `false`!
:marked
2015-10-16 23:39:30 -04:00
#### Expanding `*ng-for`
This same transformation applies to `*ng-for`. We can "de-sugar" the syntax ourselves and go from ...
```
<little-hero *ng-for="#hero of heroes" [hero]="hero"></little-hero>
```
... to
```
<template ng-for #hero [ng-for-of]="heroes">
<little-hero [hero]="hero"></little-hero>
</template>
```
There is some additional complexity here. A repeater has more moving parts to configure
than the conditional `ng-if`.
And it's pretty clear why we prefer the `*ng-for` syntax to writing out this expanded HTML ourselves.
But the strategy isn't new and need not be mysterious.
We set up the `ng-for` directive (and its friends) on the `<template>`,
move our `<little-hero>` component inside the `<template>` tags and
use the `#hero` local template variable to convey data
from the outer `<template>` to the
2015-10-16 23:39:30 -04:00
inner `<little-hero>` component.
2015-10-16 23:39:30 -04:00
That nifty trick with the `#hero` local template variable is our next topic.
2015-10-16 23:39:30 -04:00
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
<a id="local-vars"></a>
## Local template variables
2015-10-16 23:39:30 -04:00
A **local template variable** is a vehicle for moving data across element lines.
2015-10-16 23:39:30 -04:00
In the “[* and &lt;templates>](#star-template)” segment we learned how Angular can expand
an `*ng-for` on a component tag into a `<template>` that wraps the component.
In the resulting HTML, Angular passes the hero for the current iteration from the outer `<template>`
2015-10-16 23:39:30 -04:00
to the inner `<little-hero>` component by means of a local template variable called `hero`.
```
<!-- ng-for w/ little-hero Component inside a template element -->
<template ng-for #hero [ng-for-of]="heroes">
<little-hero [hero]="hero"></little-hero>
</template>
```
2015-10-16 23:39:30 -04:00
We declare the variable by prefixing its identifier
with the **“hash/pound” symbol (#)** as in `#hero`. Angular recognizes the '#' + identifier
combination, creates the variable, and assigns its value.
2015-10-16 23:39:30 -04:00
.l-sub-section
:marked
2015-10-16 23:39:30 -04:00
`var-` is the “cannonical” alternative to "#". We could have declared our variable as `var-hero`.
:marked
2015-10-16 23:39:30 -04:00
We can **reference a local template variable on the same element, on a sibling element, or on
any of its children**.
2015-10-16 23:39:30 -04:00
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>
2015-10-16 23:39:30 -04:00
<!-- officFax refers to the input element; pass its `value` to an event handler -->
<input var-office-fax placeholder="phone number">
<button (click)="callFax(officeFax.value)">Fax</button>
```
#### Observations
The value assigned to the variable depends upon the context.
2015-10-16 23:39:30 -04:00
When a directive is present on the element, as it is in the `<little-hero>` component example,
the directive sets the value.
Accordingly, it is the `ng-for` directive
2015-10-16 23:39:30 -04:00
that sets the `hero` variable to the current iteration item from the `heroes` array.
When there is no directive present, as in the button examples,
Angular sets the variable to the element itself.
2015-10-16 23:39:30 -04:00
Were passing the `input` element objects across to the
buttons where they become arguments to the `call()` methods.
Remember that the HTML parser forces the identifier to lower-case.
If we want to reference a camel-case name,
2015-10-16 23:39:30 -04:00
we insert dashes (-) before each capital letter as we did for `officeFax`.
Let's look at one final example, a Form, the poster child for local template variables:
```
<form (ng-submit)="onSubmit(hf)" #hf="form">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" required
ng-control="firstName"
[(ng-model)]="currentHero.firstName">
</div>
<button type="submit" [disabled]="!hf.form.valid">Submit</button>
</form>
```
The `<form>` tag is *not the native HTML form element!*
2015-10-16 23:39:30 -04:00
It's an Angular built-in directive that wraps the native `Form` element and
endows it with additional form super powers.
2015-10-16 23:39:30 -04:00
.l-sub-section
:marked
We know it's the Angular built-in `form` directive
2015-10-16 23:39:30 -04:00
because we imported the `FORM_DIRECTIVES` collection
and added it to the parent component's `directives` array.
2015-10-16 23:39:30 -04:00
Learn more about forms in the [Forms](./forms.html) chapter.
:marked
2015-10-16 23:39:30 -04:00
We assign the form object to the `hf` ("hero form") local template variable
and use it twice.
1. We pass it to the `onSubmit` method of the parent component process form values.
1. We disable the submit button if the form is invalid which we
detect by evaluating `hf.form.valid`.
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
<a id="inputs-outputs"></a>
## Input and Output Properties
When Directives are the **targets of data binding**, they must expose **input** and **output** properties.
2015-10-16 23:39:30 -04:00
Let us confess that these “input” and “output” terms are generic, overloaded and somewhat confusing in the present context.
Directives can have many bindable properties.
Why are only a few of them inputs or output? Or none at all?
2015-10-16 23:39:30 -04:00
Who says a directive property has an in or out direction?
2015-10-16 23:39:30 -04:00
We may quarrel about the word choice but the distinction between regular properties
and input/out properties is important.
2015-10-16 23:39:30 -04:00
**Input/output properties can be targets of a binding expression**.
A directive property in binding target position on the left-hand side of a binding expression
2015-10-16 23:39:30 -04:00
must be either an input or an output
Keep in mind that a Component is also a Directive. Well say it another way:
2015-10-16 23:39:30 -04:00
**The target of a directive binding must be must be either an input or an output.**
In this chapter weve focused on binding to Component members inside template expressions on the right-hand side of the binding declaration.
2015-10-16 23:39:30 -04:00
A member in that position may be thought of as a binding “data source”. It's not a target for binding.
2015-10-16 23:39:30 -04:00
In the following example, `iconUrl` and `onSave` are members of a Component. They are both referenced within template expressions on the right.
```
<img [src]="iconUrl"/>
<button (click)="onSave()">Save</button>
```
They are *not inputs or outputs* of the component. They serve as data sources for their bindings.
2015-10-16 23:39:30 -04:00
Now look at the `HeroDetailComponent` when it is the **target of a binding**.
```
<hero-detail [hero]="currentHero" (deleted)="onDeleted($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.
2015-10-16 23:39:30 -04:00
Therefore `HeroDetail.hero` is an ***input*** property from the perspective of `HeroDetail`.
**Events stream *out* of the `HeroDetail.deleted` target property** (which is an `EventEmitter`) 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
2015-10-16 23:39:30 -04:00
with decorators as input and output properties.
```
class HeroDetailComponent {
2015-10-16 23:39:30 -04:00
@Input()
hero: Hero;
2015-10-16 23:39:30 -04:00
@Output()
deleted = new EventEmitter<Hero>();
2015-10-16 23:39:30 -04:00
onDelete() {
this.deleted.next(this.hero);
}
}
```
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
<a id="expression-ops"></a>
## Template Expression Operators
The template expression language employs a subset of JavaScript syntax supplemented with some special operators
2015-11-01 00:13:18 -04:00
for specific scenarios. We'll cover two of them, "pipe" and "Elvis".
2015-10-16 23:39:30 -04:00
<a id="pipe"></a>
### The Pipe Operator ( | )
The result of an expression may require some transformation before were 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](./pipes.html) are a good choice for small transformations such as these.
2015-10-16 23:39:30 -04:00
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 ( | )**:
code-example(format="" language="html").
&lt;!-- Force title to uppercase -->
&lt;div>{{ title | uppercase }}&lt;/div>
:marked
2015-10-16 23:39:30 -04:00
The pipe operator passes the result of an expression on the left to a pipe function on the right.
We can also chain expressions through multiple pipes
2015-10-16 23:39:30 -04:00
code-example(format="" language="html").
&lt;!-- Pipe chaining: force title to uppercase, then to lowercase -->
&lt;div>{{ title | uppercase | lowercase }}</div>
:marked
2015-10-16 23:39:30 -04:00
<a id="elvis"></a>
### The Elvis Operator ( ?. ) and null property paths
2015-10-16 23:39:30 -04:00
The Angular **“Elvis” operator ( ?. )** is a fluent and convenient way to guard against null and undefined values in property paths as we see it here, protecting against a view render failure if the `currentHero` is null.
code-example(format="" language="html").
<div>The current heros name is {{currentHero?.firstName}}</div>
:marked
2015-10-16 23:39:30 -04:00
Lets elaborate on the problem and this particular solution.
2015-10-16 23:39:30 -04:00
What happens when the following data bound `title` property is null?
code-example(format="" language="html").
<div>The title is {{ title }}</div>
:marked
2015-10-16 23:39:30 -04:00
The view still renders but the displayed value is blank; we see only "`The title is`" with nothing after it.
2015-10-16 23:39:30 -04:00
Suppose the template expression involves a property path as in this next example where were displaying the `firstName` of a null hero.
code-example(format="" language="html").
<div>The null hero's name is {{nullHero.firstName}}</div>
:marked
2015-10-16 23:39:30 -04:00
JavaScript throws a null reference error and so does Angular:
code-example(format="" language="html").
TypeError: Cannot read property 'firstName' of null in [null]
:marked
2015-10-16 23:39:30 -04:00
Surprisingly, the entire view just disappears.
We could claim that this is reasonable behavior if we believe that the `hero` property must never be null.
2015-10-16 23:39:30 -04:00
If it must never be null and yet it is null,
we've made a programming error that should be caught and fixed.
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
2015-10-16 23:39:30 -04:00
the null property path should display as blank as the `title` property does.
2015-10-16 23:39:30 -04:00
Unfortunately, our app crashes when the `currentHero` is null.
2015-10-16 23:39:30 -04:00
We can code around that problem with [`ng-if`](#ng-if)
code-example(format="" language="html").
2015-10-16 23:39:30 -04:00
&lt;!-- No hero, div not displayed, no error -->
&lt;div *ng-if="nullHero">The null hero's name is {{nullHero?.firstName}}</div>
:marked
This approach has merit but its cumbersome, especially if the property path is long.
2015-10-16 23:39:30 -04:00
Imagine guarding against a null somewhere in a long property path such as `a.b.c.d`.
2015-10-16 23:39:30 -04:00
The Angular **“Elvis” operator ( ?. )** is a more fluent and convenient way to guard against nulls in property paths.
code-example(format="" language="html").
&lt;!-- No hero, no problem! -->
&lt;div>The null hero's name is {{nullHero?.firstName}}</div>
:marked
2015-10-16 23:39:30 -04:00
Its great with long property paths too:
```
a?.b?.c?.d
```
2015-10-16 23:39:30 -04:00
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
## What Next?
Weve completed our survey of Template Syntax. Time to put that knowledge to work as we write our own Components and Directives.