2015-10-15 03:51:24 -04:00
include ../../../../_includes/_util-fns
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
Our Angular application manages what the user sees and does through the interaction of a Component class instance (the *component*) and its user-facing template.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Many of us are familiar with the component/template duality from our experience with model-view-controller (MVC) or model-view-viewmodel (MVVM). In Angular, the component plays the part of the controller/viewmodel, and the template represents the view.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Let’ s find out what it takes to write a template for our view. We’ ll cover these basic elements of template syntax:
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
* [HTML](#html)
* [Interpolation](#interpolation)
* [Template expressions](#template-expressions)
* [Template statements](#template-statements)
* [Binding syntax](#binding-syntax)
* [Property binding](#property-binding)
* [Attribute, class, and style bindings](#other-bindings)
* [Event binding](#event-binding)
* [Two-way data binding with `NgModel`](#ngModel)
* [Built-in directives](#directives)
* [* and <template>](#star-template)
* [Local template variables](#local-vars)
* [Input and output properties](#inputs-outputs)
* [Template expression operators](#expression-operators)
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
[Run the live example](/resources/live-examples/template-syntax/ts/plnkr.html)
2015-10-16 23:39:30 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2015-10-16 23:39:30 -04:00
## HTML
2016-01-28 19:01:39 -05:00
HTML is the language of the Angular template. Our [QuickStart](./quickstart.html) application had a template that was pure HTML:
2015-10-16 23:39:30 -04:00
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'my-first-app')(format=".")
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
Almost all HTML syntax is valid template syntax. The `<script>` element is a notable exception; it is forbidden, eliminating the risk of JavaScript injection attacks. (In practice, `<script>` is simply ignored.)
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
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.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05: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-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Let’ s turn to the first form of data binding — interpolation — to see how much richer template HTML can be.
2015-10-16 23:39:30 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
: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-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'first-interpolation')(format=".")
2015-11-10 13:31:46 -05:00
: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.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'title+image')(format=".")
2015-11-10 13:31:46 -05:00
: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.
2015-11-10 13:31:46 -05:00
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:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'sum-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
The expression can invoke methods of the host component, as we do here with `getVal()`:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'sum-2')(format=".")
2015-11-10 13:31:46 -05:00
: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
2015-11-10 13:31:46 -05:00
We appear to be inserting the result between element tags and assigning to attributes.
2016-01-28 19:01:39 -05:00
It's convenient to think so, and we rarely suffer for this mistake.
But it is not literally true. Interpolation is a special syntax that Angular converts into a
[property binding](#property-binding), as we'll explain below.
2015-10-16 23:39:30 -04:00
2016-01-28 19:01:39 -05:00
But first, let's take a closer look at template expressions and statements.
2015-10-16 23:39:30 -04:00
2016-01-10 20:07:19 -05:00
<a id="template-expressions"></a>
2015-10-16 23:39:30 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
## Template expressions
A template **expression** produces a value.
Angular executes the expression and assigns it to a property of a binding target;
the target might be an HTML element, a component, or a directive.
2016-01-10 20:07:19 -05:00
We put a template expression within the interpolation braces when we wrote `{{1 + 1}}`.
2016-01-28 19:01:39 -05:00
We’ ll see template expressions again in the [property binding](#property-binding) section,
appearing in quotes to the right of the `=` symbol as in `[property]="expression"`.
2016-01-10 20:07:19 -05:00
2016-01-28 19:01:39 -05:00
We write template expressions in a language that looks like JavaScript.
Many JavaScript expressions are legal template expressions, but not all.
JavaScript expressions that have or promote side effects are prohibited,
including:
2016-01-19 02:54:27 -05:00
* assignments (`=`, `+=`, `-=`)
2016-01-10 20:07:19 -05:00
* the `new` operator
* chaining expressions with `;` or `,`
2016-01-28 19:01:39 -05:00
* increment and decrement operators (`++` and `--`)
2016-01-10 20:07:19 -05:00
Other notable differences from JavaScript syntax include:
2016-01-28 19:01:39 -05:00
* no support for the bitwise operators `|` and `&`
2016-01-10 20:07:19 -05:00
* new [template expression operators](#expression-operators), such as `|` and `?.`
2016-01-28 19:01:39 -05:00
2016-01-10 20:07:19 -05:00
<a id="expression-context"></a>
2016-01-28 19:01:39 -05:00
### Expression context
Perhaps more surprising, template expressions cannot refer to anything in the global namespace.
They can’ t refer to `window` or `document`. They can’ t call `console.log` or `Math.max`.
They are restricted to referencing members of the expression context.
The *expression context* is typically the **component instance**, which is
the source of binding values.
2015-11-10 13:31:46 -05:00
2016-01-10 20:07:19 -05:00
When we see *title* wrapped in double-curly braces, <code>{{title}}</code>,
we know that `title` is a property of the data-bound component.
When we see *isUnchanged* in `[disabled]="isUnchanged"`,
we know we are referring to that component's `isUnchanged` property.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
The component itself is usually the expression *context*, in which case
2015-11-10 13:31:46 -05:00
the template expression usually references that component.
2016-01-28 19:01:39 -05:00
The expression context can include objects <!-- CHECK: is that an ok wording change? -->
other than the component.
2016-01-10 20:07:19 -05:00
A [local template variable](#local-vars) is one such alternative context object.
2016-01-28 19:01:39 -05:00
2016-01-10 20:07:19 -05:00
<a id="no-side-effects"></a>
2016-01-28 19:01:39 -05:00
### Expression guidelines
Template expressions can make or break an application.
Please follow these guidelines:
* [No visible side effects](#no-visible-side-effects)
* [Quick execution](#quick-execution)
* [Simplicity](#simplicity)
* [Idempotence](#idempotence)
The only exceptions to these guidelines are specific circumstances that you thoroughly understand.
#### No visible side effects
A template expression should not change any application state other than the value of the
2016-01-10 20:07:19 -05:00
target property.
2016-01-28 19:01:39 -05:00
2016-01-10 20:07:19 -05:00
This rule is essential to Angular's "unidirectional data flow" policy.
We should never worry that reading a component value might change some other displayed value.
The view should be stable throughout a single rendering pass.
2016-01-28 19:01:39 -05:00
#### Quick execution
2016-01-10 20:07:19 -05:00
Angular executes template expressions more often than we might think.
Expressions should finish quickly or the user experience may drag, especially on slower devices.
2016-01-28 19:01:39 -05:00
#### Simplicity
Although it's possible to write quite complex template expressions, we really shouldn't.
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.
#### Idempotence
2016-01-10 20:07:19 -05:00
An [idempotent](https://en.wikipedia.org/wiki/Idempotence) expression is ideal because
2016-01-28 19:01:39 -05:00
it is free of side effects and improves Angular's change detection performance.
2016-01-10 20:07:19 -05:00
In Angular terms, an idempotent expression always returns *exactly the same thing* until
one of its dependent values changes.
2016-01-28 19:01:39 -05:00
2016-01-10 20:07:19 -05:00
Dependent values should not change during a single turn of the JavaScript virtual machine.
If an idempotent expression returns a string or a number, it returns the same string or number
when called twice in a row. If the expression returns an object (including a `Date` or `Array`),
2016-01-28 19:01:39 -05:00
it returns the same object *reference* when called twice in a row.
2016-01-10 20:07:19 -05:00
<a id="template-statements"></a>
.l-main-section
:marked
2016-01-28 19:01:39 -05:00
## Template statements
A template **statement** responds to an **event** raised by a binding target
2016-01-10 20:07:19 -05:00
such as an element, component, or directive.
2016-01-28 19:01:39 -05:00
We’ ll see template statements in the [event binding](#event-binding) section,
appearing in quotes to the right of the `=` symbol as in `(event)="statement"`.
A template statement *has a side effect*.
2016-01-10 20:07:19 -05:00
It's how we update application state from user input.
There would be no point to responding to an event otherwise.
.l-sub-section
:marked
Responding to events is the other side of Angular's "unidirectional data flow".
We're free to change anything, anywhere, during this turn of the JavaScript virtual machine.
:marked
2016-01-28 19:01:39 -05:00
Like template expressions, template *statements* use a language that looks like JavaScript.
The template statement parser is different than the template expression parser and
specifically supports both basic assignment (`=`) and chaining expressions with semicolons (`;`) and commas (`,`).
2016-01-10 20:07:19 -05:00
However, certain JavaScript syntax is not allowed:
* the `new` operator
* increment and decrement operators, `++` and `--`
2016-01-28 19:01:39 -05:00
* operator assignment, such as `+=` and `-=`
* the bitwise operators `|` and `&`
2016-01-10 20:07:19 -05:00
* the [template expression operators](#expression-operators)
2016-01-28 19:01:39 -05:00
### Statement context
As with expressions, statements cannot refer to anything in the global namespace.
They can’ t refer to `window` or `document`. They can’ t call `console.log` or `Math.max`.
Statements are restricted to referencing members of the statement context.
The statement context is typically the **component instance** to which we are binding an event.
2016-01-10 20:07:19 -05:00
The *onSave* in `(click)="onSave()"` is sure to be a method of the data-bound component instance.
2016-01-28 19:01:39 -05:00
2016-01-10 20:07:19 -05:00
The statement context may include an object other than the component.
2016-01-28 19:01:39 -05:00
A [local template variable](#local-vars) is one such alternative context object.
2016-01-10 20:07:19 -05:00
We'll frequently see the reserved `$event` symbol in event binding statements,
2016-01-28 19:01:39 -05:00
representing the "message" or "payload" of the raised event.
### Statement guidelines
As with expressions, avoid writing complex template statements.
A method call or simple property assignment should be the norm.
Now that we have a feel for template expressions and statements,
we’ re ready to learn about the varieties of data binding syntax beyond interpolation.
2015-10-16 23:39:30 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2015-10-16 23:39:30 -04:00
<a id="binding-syntax"></a>
2016-01-28 19:01:39 -05:00
## Binding syntax: An overview
Data binding is a mechanism for coordinating what users see with application data values.
2016-01-10 20:07:19 -05:00
While we could push values to and pull values from HTML,
2015-11-10 13:31:46 -05:00
the application is easier to write, read, and maintain if we turn these chores over to a binding framework.
2016-01-10 20:07:19 -05:00
We simply declare bindings between binding sources and target HTML elements and let the framework do the work.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
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.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
We can group all bindings into three categories by the direction in which data flows.
2016-01-10 20:07:19 -05:00
Each category has its distinctive syntax:
2015-10-16 23:39:30 -04:00
table
tr
2016-01-28 19:01:39 -05:00
th Data direction
2015-10-16 23:39:30 -04:00
th Syntax
2016-01-28 19:01:39 -05:00
th Binding type
2015-10-16 23:39:30 -04:00
tr
2016-01-28 19:01:39 -05:00
td One-way<br>from data source<br>to view target
2015-10-16 23:39:30 -04:00
td
code-example(format="" ).
{{expression}}
[target] = "expression"
bind-target = "expression"
2015-11-10 13:31:46 -05:00
td.
2015-10-16 23:39:30 -04:00
Interpolation<br>
Property<br>
Attribute<br>
Class<br>
Style
tr
2016-01-28 19:01:39 -05:00
td One-way<br>from view target<br>to data source
2015-10-16 23:39:30 -04:00
td
code-example(format="" ).
2016-01-10 20:07:19 -05:00
(target) = "statement"
on-target = "statement"
2015-10-16 23:39:30 -04:00
td Event
tr
2016-01-28 19:01:39 -05:00
td Two-way
2015-10-16 23:39:30 -04:00
td
code-example(format="" ).
[(target)] = "expression"
bindon-target = "expression"
td Two-way
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
Binding types other than interpolation have a **target name** to the left of the equal sign,
2016-01-10 20:07:19 -05:00
either surrounded by punctuation (`[]`, `()`) or preceded by a prefix (`bind-`, `on-`, `bindon-`).
2015-10-16 23:39:30 -04:00
2016-01-28 19:01:39 -05:00
What is that target? Before we can answer that question, we must challenge ourselves to look at template HTML in a new way.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
### A new mental model
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
With all the power of data binding and our ability to extend the HTML vocabulary
2016-01-28 19:01:39 -05:00
with custom markup, it is tempting to think of template HTML as *HTML Plus*.
Well, it *is* HTML Plus.
2015-11-10 13:31:46 -05:00
But it’ s also significantly different than the HTML we’ re used to.
2015-10-16 23:39:30 -04:00
We really need a new mental model.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
In the normal course of HTML development, we create a visual structure with HTML elements, and
2015-12-07 16:31:26 -05:00
we modify those elements by setting element attributes with string constants.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'img+button')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2015-10-16 23:39:30 -04:00
We still create a structure and initialize attribute values this way in Angular templates.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Then we learn to create new elements with components that encapsulate HTML
2015-12-07 16:31:26 -05:00
and drop them into our templates as if they were native HTML elements
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'hero-detail-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
That’ s HTML Plus.
2015-11-10 13:31:46 -05:00
2015-12-07 16:31:26 -05:00
Now we start to learn about data binding. The first binding we meet might look like this:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'disabled-button-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2015-11-10 13:31:46 -05:00
We’ ll 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 we’ re binding to the button's `disabled` attribute and setting
it to the current value of the component’ s `isUnchanged` property.
2015-11-10 13:31:46 -05:00
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.
2016-01-10 20:07:19 -05:00
We are setting the *properties* of DOM elements, components, and directives.
2015-11-10 13:31:46 -05:00
2015-10-20 19:10:44 -04:00
.l-sub-section
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
### HTML attribute vs. DOM property
2015-11-10 13:31:46 -05:00
2015-10-20 19:10:44 -04:00
The distinction between an HTML attribute and a DOM property is crucial to understanding how Angular binding works.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
**Attributes are defined by HTML. Properties are defined by the DOM (Document Object Model).**
2015-11-10 13:31:46 -05:00
2015-10-20 19:10:44 -04:00
* A few HTML attributes have 1:1 mapping to properties. `id` is one example.
2015-11-10 13:31:46 -05:00
2015-10-20 19:10:44 -04:00
* Some HTML attributes don't have corresponding properties. `colspan` is one example.
2015-11-10 13:31:46 -05:00
2015-10-20 19:10:44 -04:00
* Some DOM properties don't have corresponding attributes. `textContent` is one example.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
* Many HTML attributes appear to map to properties ... but not in the way we might think!
2015-11-10 13:31:46 -05:00
2015-10-20 19:10:44 -04:00
That last category can be especially confusing ... until we understand this general rule:
2015-11-10 13:31:46 -05:00
**Attributes *initialize* DOM properties and then they are done.
2016-01-28 19:01:39 -05:00
Property values can change; attribute values can't.**
2015-10-20 19:10:44 -04:00
2015-11-10 13:31:46 -05:00
For example, when the browser renders `<input type="text" value="Bob">`, it creates a
corresponding DOM node with a `value` property *initialized* to "Bob".
2015-10-20 19:10:44 -04:00
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"`
2015-11-10 13:31:46 -05:00
2015-10-20 19:10:44 -04:00
The HTML attribute `value` specifies the *initial* value; the DOM `value` property is the *current* value.
2015-11-10 13:31:46 -05:00
2015-10-20 19:10:44 -04:00
The `disabled` attribute is another peculiar example. A button's `disabled` *property* is
2015-11-10 13:31:46 -05:00
`false` by default so the button is enabled.
2015-10-20 19:10:44 -04:00
When we add the `disabled` *attribute*, it's presence alone initializes the button's `disabled` *property* to `true`
so the button is disabled.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Adding and removing the `disabled` *attribute* disables and enables the button. The value of the *attribute* is irrelevant,
2015-10-20 19:10:44 -04:00
which is why we cannot enable a button by writing `<button disabled="false">Still Disabled</button>`.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Setting the button's `disabled` *property* (say, with an Angular binding) disables or enables the button.
2015-11-10 13:31:46 -05:00
The value of the *property* matters.
2015-10-20 19:10:44 -04:00
**The HTML attribute and the DOM property are not the same thing even when they have the same name.**
2015-11-10 13:31:46 -05:00
:marked
2015-10-16 23:39:30 -04:00
This is so important, we’ ll say it again.
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
**Template binding works with *properties* and *events*, not *attributes*.**
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
.callout.is-helpful
header A world without attributes
2015-11-10 13:31:46 -05:00
: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.
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
With this model firmly in mind, let's learn about binding targets.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
### Binding targets
2015-10-16 23:39:30 -04:00
The **target of a data binding** is something in the DOM.
2015-11-10 13:31:46 -05:00
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
2016-01-28 19:01:39 -05:00
th Binding type
2015-10-16 23:39:30 -04:00
th Target
th Examples
tr
td Property
2015-11-10 13:31:46 -05:00
td.
2016-01-28 19:01:39 -05:00
Element property<br>
Component property<br>
2015-10-16 23:39:30 -04:00
Directive property
td
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-syntax-1')(format=".")
2015-10-16 23:39:30 -04:00
tr
td Event
2015-11-10 13:31:46 -05:00
td.
2016-01-28 19:01:39 -05:00
Element event<br>
Component event<br>
Directive event
2015-10-16 23:39:30 -04:00
td
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-syntax-1')(format=".")
2015-10-16 23:39:30 -04:00
tr
td Two-way
2015-11-10 13:31:46 -05:00
td.
2016-01-28 19:01:39 -05:00
Event and property
2015-10-16 23:39:30 -04:00
td
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', '2-way-binding-syntax-1')(format=".")
2015-10-16 23:39:30 -04:00
tr
td Attribute
2015-11-10 13:31:46 -05:00
td.
2015-10-16 23:39:30 -04:00
Attribute
(the exception)
td
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'attribute-binding-syntax-1')(format=".")
2015-10-16 23:39:30 -04:00
tr
td Class
2015-11-10 13:31:46 -05:00
td.
2016-01-28 19:01:39 -05:00
<code>class</code> property
2015-10-16 23:39:30 -04:00
td
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-syntax-1')(format=".")
2015-10-16 23:39:30 -04:00
tr
td Style
2015-11-10 13:31:46 -05:00
td.
2016-01-28 19:01:39 -05:00
<code>style</code> property
2015-10-16 23:39:30 -04:00
td
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'style-binding-syntax-1')(format=".")
2015-11-10 13:31:46 -05:00
</div>
:marked
2015-10-16 23:39:30 -04:00
Let’ s descend from the architectural clouds and look at each of these binding types in concrete detail.
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
## Property binding
We write a template **property binding** when we want to set a property of a view element to the value of
2016-01-10 20:07:19 -05:00
a [template expression](#template-expressions).
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
The most common property binding sets an element property to a component property value. An example is
binding the `src` property of an image element to a component’ s `heroImageUrl` property:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Another example is disabling a button when the component says that it `isUnchanged`:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-2')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Another is setting a property of a directive:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-3')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Yet another is setting the model property of a custom component (a great way
for parent and child components to communicate):
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-4')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-10 20:07:19 -05:00
### One-way *in*
2016-01-28 19:01:39 -05:00
People often describe property binding as *one-way data binding* because it flows a value in one direction,
2016-01-10 20:07:19 -05:00
from a component’ s data property into a target element property.
2016-01-28 19:01:39 -05:00
2016-01-10 20:07:19 -05:00
We cannot use property binding to pull values *out* of the target element.
We can't bind to a property of the target element to read it. We can only set it.
.l-sub-section
:marked
Nor can we use property binding to *call* a method on the target element.
2016-01-28 19:01:39 -05:00
2016-01-10 20:07:19 -05:00
If the element raises events we can listen to them with an [event binding](#event-binding).
2016-01-28 19:01:39 -05:00
2016-01-10 20:07:19 -05:00
If we must read a target element property or call one of its methods,
2016-01-28 19:01:39 -05:00
we'll need a different technique.
See the API reference for
[viewChild](../api/core/ViewChild-var.html) and
2016-01-10 20:07:19 -05:00
[contentChild](../api/core/ContentChild-var.html).
2015-10-16 23:39:30 -04:00
2016-01-10 20:07:19 -05:00
:marked
2016-01-28 19:01:39 -05:00
### Binding target
A name between enclosing square brackets identifies the target property. The target property in the following code is the image element’ s `src` property.
2015-12-07 16:31:26 -05:00
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Some people prefer the `bind-` prefix alternative, known as the *canonical form*:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-5')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2015-10-16 23:39:30 -04:00
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.
2015-11-10 13:31:46 -05:00
Element properties may be the more common targets,
2016-01-28 19:01:39 -05:00
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:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-3')(format=".")
2015-12-07 16:31:26 -05:00
2015-10-16 23:39:30 -04:00
.l-sub-section
2015-11-10 13:31:46 -05:00
:marked
Technically, Angular is matching the name to a directive [input](#inputs-outputs),
one of the property names listed in the directive’ s `inputs` array or a property decorated with `@Input()`.
2015-10-16 23:39:30 -04:00
Such inputs map to the directive’ s own properties.
2015-11-10 13:31:46 -05:00
: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.
2016-01-28 19:01:39 -05:00
### Template expressions in property binding
As we've already discussed, evaluation of a template 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.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05: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.
2015-11-10 13:31:46 -05:00
The expression could call something like `getFoo()`. Only we know what `getFoo()` does.
2016-01-28 19:01:39 -05: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 to methods that return values and do no more.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
The template expression should evaluate to a value of the type expected by the target property. Most native element properties expect a string. For example, the image `src` should be set to a string that's an URL for the resource providing the image. On the other hand, the `disabled` property of a button expects a Boolean value, so an expression that's assigned to `disabled` should evaluate to `true` or `false`.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
The `hero` property of the `HeroDetail` component expects a `Hero` object, which is exactly what we’ re sending in the property binding:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-4')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
This is good news.
If `hero` were an attribute, we could not set it to a `Hero` object.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-6')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2015-11-10 13:31:46 -05:00
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
That’ s good to know but not helpful to us when we're trying to pass a significant data object
2015-11-10 13:31:46 -05:00
from one component element to another.
2016-01-28 19:01:39 -05:00
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-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
### Property binding or interpolation?
We often have a choice between interpolation and property binding. The following binding pairs do the same thing:
2015-12-15 17:10:10 -05:00
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-vs-interpolation')(format=".")
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
Interpolation is 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.
2015-11-10 13:31:46 -05:00
There is no technical reason to prefer one form to the other.
2016-01-28 19:01:39 -05:00
We lean toward readability, which tends to favor interpolation.
2015-11-10 13:31:46 -05:00
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.
2015-10-15 03:51:24 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2015-10-16 23:39:30 -04:00
<a id="other-bindings"></a>
2016-01-28 19:01:39 -05:00
## Attribute, class, and style bindings
The template syntax provides specialized one-way bindings for scenarios less well suited to property binding.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
### Attribute binding
We can set the value of an attribute directly with an **attribute binding**.
2015-10-16 23:39:30 -04:00
.l-sub-section
2015-11-10 13:31:46 -05:00
: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.
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05: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-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
**We must use attribute binding when there is no element property to bind.**
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05: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
2015-11-10 13:31:46 -05:00
table span attributes. They are pure attributes.
2016-01-28 19:01:39 -05:00
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-11-10 13:31:46 -05:00
2016-01-15 14:26:34 -05:00
We become painfully aware of this fact when we try to write something like this:
2015-10-16 23:39:30 -04:00
code-example(language="html").
2015-12-13 23:10:03 -05:00
<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
We get this error:
2015-10-16 23:39:30 -04:00
code-example(format="", language="html").
2015-11-10 13:31:46 -05:00
Template parse errors:
2015-10-16 23:39:30 -04:00
Can't bind to 'colspan' since it isn't a known native property
2015-11-10 13:31:46 -05:00
:marked
As the message says, the `<td>` element does not have a `colspan` property.
2016-01-28 19:01:39 -05:00
It has the "colspan" *attribute*, but
interpolation and property binding can set only *properties*, not attributes.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
We need attribute bindings to create and bind to such attributes.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Attribute binding syntax resembles property binding.
Instead of an element property between brackets, we start with the prefix **`attr`**,
followed by a dot (`.`) and the name of the attribute. We then set the attribute
value, using an expression that resolves to a string.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Here we bind `[attr.colspan]` to a calculated value:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'attrib-binding-colspan')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2015-10-16 23:39:30 -04:00
Here's how the table renders:
<table border="1px">
2015-12-15 17:10:10 -05:00
<tr><td colspan="2">One-Two</td></tr>
2015-12-07 16:31:26 -05:00
<tr><td>Five</td><td>Six</td></tr>
2015-10-16 23:39:30 -04:00
</table>
2016-01-28 19:01:39 -05:00
One of the primary use cases for attribute binding
is to set ARIA attributes, as in this example:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'attrib-binding-aria')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
### Class binding
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
We can add and remove CSS class names from an element’ s `class` attribute with
a **class binding**.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Class binding syntax resembles property binding.
Instead of an element property between brackets, we start with the prefix `class`,
optionally followed by a dot (`.`) and the name of a CSS class: `[class.class-name]`.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
The following examples show how to add and remove the application's "special" class
with class bindings. Here's how we set the attribute without binding:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
We can replace that with a binding to a string of the desired class names; this is an all-or-nothing, replacement binding.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-2')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Finally, we can bind to a specific class name.
Angular adds the class when the template expression evaluates to something truthy.
It removes the class when the expression is falsey.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-3')(format=".")
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
.l-sub-section
2015-11-10 13:31:46 -05:00
:marked
While this is a fine way to toggle a single class name,
2015-12-13 23:10:03 -05:00
we generally prefer the [NgClass directive](#ngClass) for managing multiple class names at the same time.
2015-10-16 23:39:30 -04:00
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
### Style binding
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
We can set inline styles with a **style binding**.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Style binding syntax resembles property binding.
Instead of an element property between brackets, we start with the prefix `style`,
followed by a dot (`.`) and the name of a CSS style property: `[style.style-property]`.
2015-11-10 13:31:46 -05:00
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'style-binding-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Some style binding styles have unit extension. Here we conditionally set the `fontSize` in “em” and “%” units .
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'style-binding-2')(format=".")
2015-12-07 16:31:26 -05:00
2015-10-16 23:39:30 -04:00
.l-sub-section
2015-11-10 13:31:46 -05:00
:marked
While this is a fine way to set a single style,
2015-12-13 23:10:03 -05:00
we generally prefer the [NgStyle directive](#ngStyle) when setting several inline styles at the same time.
2015-10-16 23:39:30 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
## Event binding
The bindings we’ ve met so far flow data in one direction: *from the component to an element*.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Users don’ t just stare at the screen. They enter text into input boxes. They pick items from lists.
They click buttons. Such user actions may result in a flow of data in the opposite direction:
*from an element to the component*.
2015-11-10 13:31:46 -05:00
The only way to know about a user action is to listen for certain events such as
2016-01-28 19:01:39 -05:00
keystrokes, mouse movements, clicks, and touches.
We declare our interest in user actions through Angular event binding.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Event binding syntax consists of a **target event** within parentheses on the left of an equal sign, and a quoted
[template statement](#template-statements) on the right.
The following event binding listens for the button’ s click event, calling
the component's `onSave()` method whenever a click occurs:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
### Target event
A **name between enclosing parentheses** — for example, `(keyup)` —
identifies the target event. In the following example, the target is the button’ s click event.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Some people prefer the `on-` prefix alternative, known as the *canonical form*:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-2')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2015-11-10 13:31:46 -05:00
Element events may be the more common targets, but Angular looks first to see if the name matches an event property
2016-01-28 19:01:39 -05:00
of a known directive, as it does in the following example:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-3')(format=".")
2015-11-10 13:31:46 -05:00
:marked
2015-12-15 17:10:10 -05:00
If the name fails to match an element event or an output property of a known directive,
2015-12-07 16:31:26 -05:00
Angular reports an “unknown directive” error.
2015-10-16 23:39:30 -04:00
2016-01-10 20:07:19 -05:00
### $event and event handling statements
2016-01-28 19:01:39 -05:00
In an event binding, Angular sets up an event handler for the target event.
2015-11-10 13:31:46 -05:00
2016-01-10 20:07:19 -05:00
When the event is raised, the handler executes the template statement.
The template statement typically involves a receiver that wants to do something
2016-01-28 19:01:39 -05:00
in response to the event, such as take a value from the HTML control and store it
2015-11-10 13:31:46 -05:00
in a model.
2016-01-28 19:01:39 -05:00
The binding conveys information about the event, including data values, through
2015-11-10 13:31:46 -05:00
an **event object named `$event`**.
2016-01-28 19:01:39 -05:00
The shape of the event object is determined by the target event itself.
2015-11-10 13:31:46 -05:00
If the target event is a native DOM element event, the `$event` is a
2016-01-28 19:01:39 -05:00
[DOM event object]( https://developer.mozilla.org/en-US/docs/Web/Events),
with properties such as `target` and `target.value`.
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
Consider this example:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'without-NgModel')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
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.
2016-01-10 20:07:19 -05:00
When the user makes changes, the `input` event is raised, and the binding executes the statement within a context that includes the DOM event object, `$event`.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
To update the `firstName` property, we must get the changed text by following
the path `$event.target.value`.
2015-11-10 13:31:46 -05:00
2015-12-15 17:10:10 -05:00
If the event belongs to a directive (remember: components are directives), `$event` has whatever shape the directive chose to produce.
2016-01-28 19:01:39 -05:00
<a id="eventemitter"></a>
<a id="custom-event"></a>
### Custom events with EventEmitter
Directives typically raise custom events with an Angular [EventEmitter](../api/core/EventEmitter-class.html).
A directive creates an `EventEmitter` and exposes it as a property.
The directive calls `EventEmitter.emit(payload)` to fire an event, passing in a message payload that can be anything.
Parent directives listen for the event by binding to this property and accessing the payload through the `$event` object.
2015-12-15 17:10:10 -05:00
Consider a `HeroDetailComponent` that produces `deleted` events with an `EventEmitter`.
2016-01-28 19:01:39 -05:00
+makeExample('template-syntax/ts/app/hero-detail.component.ts',
'deleted', 'HeroDetailComponent.ts (excerpt)')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
When the user clicks a button, the component invokes the `onDeleted()` method, which emits a `Hero` object.
The `HeroDetailComponent` doesn't know how to delete a hero. Its job is to present information and
respond to user actions.
Now imagine a parent component that binds to the `HeroDetailComponent`'s `deleted` event.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
+makeExample('template-syntax/ts/app/app.component.html',
'event-binding-to-component')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
When the `deleted` event fires, Angular calls the parent component's `onHeroDeleted` method,
passing the *hero-to-delete* (emitted by `HeroDetail`) in the `$event` variable.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
The `onHeroDeleted` method has a side effect: It deletes a hero.
Side effects are not just OK, they are expected.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
Deleting the hero updates the model, perhaps triggering other changes
including queries and saves to a remote server.
These changes percolate through the system and are ultimately displayed in this and other views.
It's all good.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
//
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
### Event bubbling and propagation [TODO: reinstate this section when it becomes true]
Angular invokes the event-handling statement if the event is raised by the current element or one of its child elements.
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-bubbling')(format=".")
:marked
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 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
2016-01-28 19:01:39 -05:00
.l-sub-section
:marked
`EventEmitter` events don’ t bubble.
2015-10-16 23:39:30 -04:00
2016-01-28 19:01:39 -05:00
:marked
The result of an event binding statement determines whether
[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.
Event propagation stops if the binding statement returns a falsey value (as does a method with no return value).
Clicking the button in the next example triggers a save;
the click doesn't make it to the outer `<div>` so the div's save handler is not called.
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-no-propagation')(format=".")
:marked
Propagation continues if the statement returns a truthy value. In the next example, the click is heard by both the button
and the outer `<div>`, causing a double save.
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-propagation')(format=".")
2015-12-07 16:31:26 -05:00
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2015-12-13 23:10:03 -05:00
<a name="ngModel"></a>
2016-01-28 19:01:39 -05:00
## 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-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
The `NgModel` directive serves that purpose, as in this example:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-1')(format=".")
2016-01-10 20:07:19 -05:00
.callout.is-important
2016-01-28 19:01:39 -05:00
header
2016-01-10 20:07:19 -05:00
:marked
<span style="font-family:consolas; monospace">[()]</span> = banana in a box
:marked
To remember that the parentheses go inside the brackets, visualize a *banana in a box*.
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Alternatively, we can use the canonical prefix form:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-2')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
There’ s a story behind this construction, a story that builds on the property and event binding techniques we learned previously.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
We could have achieved the same result as `NgModel` with separate bindings to
2015-12-07 16:31:26 -05:00
the `<input>` element's `value` property and `input` event.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'without-NgModel')(format=".")
2015-12-07 16:31:26 -05:00
:marked
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?
2015-11-10 13:31:46 -05:00
2015-12-13 23:10:03 -05:00
That `ngModel` directive hides these onerous details. It wraps the element’ s `value` property, listens to the `input` event,
2015-12-07 16:31:26 -05:00
and raises its own event with the changed text ready for us to consume.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-3')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
That’ s an improvement, but it could be better.
2015-12-15 17:10:10 -05:00
2015-12-07 16:31:26 -05:00
We shouldn't have to mention the data property twice. Angular should be able to read the component’ s data property and set it
2015-12-16 17:10:27 -05:00
with a single declaration — which it can with the `[( )]` syntax:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-1')(format=".")
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
.l-sub-section
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
Internally, Angular maps the term `ngModel` to an `ngModel` input property and an
2015-12-13 23:10:03 -05:00
`ngModelChange` output property.
2016-01-28 19:01:39 -05:00
That’ s a specific example of a more general pattern in which Angular matches `[(x)]` to an `x` input property
for property binding and an `xChange` output property for event binding.
<!-- TODO: We haven't talked about input and output properties before on
this page (and barely mentioned them before in the Forms page). Introduce them better. -->
2015-11-10 13:31:46 -05:00
:marked
2015-12-15 17:10:10 -05:00
Is `[(ngModel)]` all we need? Is there ever a reason to fall back to its expanded form?
2016-01-28 19:01:39 -05:00
Well, `NgModel` can only set the target property.
2015-12-07 16:31:26 -05:00
What if we need to do something more or something different when the user changes the value?
2016-01-28 19:01:39 -05:00
Then we need to use the expanded form.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
Let's try something silly like forcing the input value to uppercase:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-4')(format=".")
2015-12-07 16:31:26 -05:00
:marked
Here are all variations in action, including the uppercase version:
figure.image-display
2015-12-14 01:29:37 -05:00
img(src='/resources/images/devguide/template-syntax/ng-model-anim.gif' alt="NgModel variations")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
<!-- TODO: Update image to use camelCase instead of kabob-case -->
2015-10-16 23:39:30 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2015-10-16 23:39:30 -04:00
<a name="directives"></a>
2016-01-28 19:01:39 -05:00
## Built-in directives
2015-11-10 13:31:46 -05:00
2015-12-15 17:10:10 -05:00
Earlier versions of Angular included over seventy built-in directives.
2016-01-28 19:01:39 -05:00
The community contributed many more, and countless private directives
have been created for internal applications.
2015-11-10 13:31:46 -05:00
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.
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?
2015-12-14 01:29:37 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2015-11-10 13:31:46 -05:00
We still benefit from directives that simplify complex tasks.
2015-10-16 23:39:30 -04:00
Angular still ships with built-in directives; just not as many.
2016-01-28 19:01:39 -05:00
We'll write our own directives, just not as many.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
This segment reviews some of the most frequently used built-in directives.
2015-11-10 13:31:46 -05:00
2015-12-13 23:10:03 -05:00
<a id="ngClass"></a>
2015-12-07 16:31:26 -05:00
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
### NgClass
2015-11-10 13:31:46 -05:00
We typically control how elements appear
by adding and removing CSS classes dynamically.
2015-12-07 16:31:26 -05:00
We can bind to `NgClass` to add or remove several classes simultaneously.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
A [class binding](#class-binding) is a good way to add or remove a *single* class.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-3a')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2015-11-10 13:31:46 -05:00
The `NgClass` directive may be the better choice
2016-01-28 19:01:39 -05:00
when we want to add or remove *many* CSS classes at the same time.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
A good way to apply `NgClass` is by binding it to a key:value control object. Each key of the object is a CSS class name; its value is `true` if the class should be added, `false` if it should be removed.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Consider a component method such as `setClasses` that manages the state of three CSS classes:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.ts', 'setClasses')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Now we can add an `NgClass` property binding that calls `setClasses`
and sets the element's classes accordingly:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgClass-1')(format=".")
2015-11-24 16:07:08 -05:00
2015-12-13 23:10:03 -05:00
<a id="ngStyle"></a>
2015-12-07 16:31:26 -05:00
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
### NgStyle
2016-01-28 19:01:39 -05:00
We can set inline styles dynamically, based on the state of the component.
Binding to `NgStyle` lets us set many inline styles simultaneously.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
A [style binding](#style-binding) is an easy way to set a *single* style value.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgStyle-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2015-11-10 13:31:46 -05:00
The `NgStyle` directive may be the better choice
2015-12-07 16:31:26 -05:00
when we want to set *many* inline styles at the same time.
2015-11-10 13:31:46 -05:00
2015-12-15 17:10:10 -05:00
We apply `NgStyle` by binding it to a key:value control object.
2016-01-28 19:01:39 -05:00
Each key of the object is a style name; its value is whatever is appropriate for that style.
2015-11-10 13:31:46 -05:00
2015-12-07 16:31:26 -05:00
Consider a component method such as `setStyles` that returns an object defining three styles:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.ts', 'setStyles')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Now we just add an `NgStyle` property binding that calls `setStyles`
and sets the element's styles accordingly:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgStyle-2')(format=".")
2015-11-24 16:07:08 -05:00
2015-12-13 23:10:03 -05:00
<a id="ngIf"></a>
2015-12-07 16:31:26 -05:00
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
### NgIf
2016-01-28 19:01:39 -05:00
We can add an element subtree (an element and its children) to the DOM by binding an `NgIf` directive to a truthy expression.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgIf-1')(format=".")
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
.alert.is-critical
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
Don't forget the asterisk (`*`) in front of `ngIf`.
For more information, see [\* and <template>](#star-template).
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Binding to a falsey expression removes the element subtree from the DOM.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgIf-2')(format=".")
2015-11-10 13:31:46 -05:00
:marked
2015-10-16 23:39:30 -04:00
#### Visibility and NgIf are not the same
2016-01-28 19:01:39 -05:00
We can show and hide an element subtree (the element and its children) with a
[class](#class-binding) or [style](#style-binding) binding:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgIf-3')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Hiding a subtree is quite different from excluding a subtree with `NgIf`.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
When we hide the element subtree, it remains in the DOM.
Components in the subtree are preserved, along with their state.
2015-12-15 17:10:10 -05:00
Angular may continue to check for changes even to invisible properties.
2016-01-28 19:01:39 -05:00
The subtree may tie up substantial memory and computing resources.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
When `NgIf` is `false`, Angular physically removes the element subtree from the DOM.
It destroys components in the subtree, along with their state, potentially freeing up substantial resources and
2015-12-07 16:31:26 -05:00
resulting in better performance for the user.
2015-11-10 13:31:46 -05:00
2015-12-15 17:10:10 -05:00
The show/hide technique is probably fine for small element trees.
2015-12-07 16:31:26 -05:00
We should be wary when hiding large trees; `NgIf` may be the safer choice. Always measure before leaping to conclusions.
2015-12-15 17:10:10 -05:00
2015-12-13 23:10:03 -05:00
<a id="ngSwitch"></a>
2015-12-07 16:31:26 -05:00
.l-main-section
:marked
2015-11-24 16:07:08 -05:00
### NgSwitch
2015-12-07 16:31:26 -05:00
We bind to `NgSwitch` when we want to display *one* element tree (an element and its children)
2016-01-28 19:01:39 -05:00
from a *set* of possible element trees, based on some condition.
Angular puts only the *selected* element tree into the DOM.
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
Here’ s an example:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgSwitch')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
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.
2015-11-10 13:31:46 -05:00
2015-12-10 12:40:54 -05:00
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.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
**At any particular moment, at most one of these templates is in the DOM.**
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
If the template’ s *match value* equals the switch value, Angular adds the template’ s subtree to the DOM. If no template is a match and there is a default template, Angular adds the default template’ s subtree to the DOM. Angular removes and destroys the subtrees of all other templates.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Three collaborating directives are at work here:
1. `ngSwitch`: bound to an expression that returns the switch value
1. `ngSwitchWhen`: bound to an expression returning a match value
1. `ngSwitchDefault`: a marker attribute on the default template
2015-10-16 23:39:30 -04:00
2015-12-13 23:10:03 -05:00
<a id="ngFor"></a>
2015-12-07 16:31:26 -05:00
.l-main-section
:marked
2015-10-16 23:39:30 -04:00
### NgFor
2016-01-28 19:01:39 -05:00
`NgFor` is a _repeater_ directive — a way to customize data display.
2015-12-15 17:10:10 -05:00
2015-12-07 16:31:26 -05:00
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.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
Here is an example of `NgFor` applied to a simple `<div>`:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgFor-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
We can also apply an `NgFor` to a component element, as in this example:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgFor-2')(format=".")
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
.alert.is-critical
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
Don't forget the asterisk (`*`) in front of `ngFor`.
For more information, see [\* and <template>](#star-template).
2015-11-10 13:31:46 -05:00
:marked
2015-12-13 23:10:03 -05:00
The text assigned to `*ngFor` is the instruction that guides the repeater process.
2015-11-10 13:31:46 -05:00
2015-12-07 16:31:26 -05:00
.l-sub-section
:marked
2016-01-28 19:01:39 -05:00
#### NgFor microsyntax
2015-12-15 17:10:10 -05:00
The string assigned to `*ngFor` is not a [template expression](#template-expressions).
2016-01-28 19:01:39 -05:00
It’ s a *microsyntax* — a little language of its own that Angular interprets. In this example, the string "#hero of heroes" means:
2015-12-15 17:10:10 -05:00
2015-12-07 16:31:26 -05:00
>*Take each hero in the `heroes` array, store it in the local `hero` variable, and make it available to the templated HTML
2016-01-28 19:01:39 -05:00
for each iteration.*
2015-12-15 17:10:10 -05:00
2015-12-07 16:31:26 -05:00
Angular translates this instruction into a new set of elements and bindings.
2016-01-28 19:01:39 -05:00
We’ ll talk about this in the next section.
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
In the two previous examples, the `ngFor` directive iterates over the `heroes` array returned by the parent component’ s `heroes` property,
stamping out instances of the element to which it is applied.
2015-12-07 16:31:26 -05:00
Angular creates a fresh instance of the template for each hero in the array.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
The hash (`#`) character before "hero" creates a [local template variable](#local-vars) called `hero`.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
We use this variable within the template to access a hero’ s properties,
as we’ re doing in the interpolation.
We can also pass the variable in a binding to a component element,
as we're doing with `hero-detail`.
2015-12-15 17:10:10 -05:00
2015-12-07 16:31:26 -05:00
#### NgFor with index
2016-01-28 19:01:39 -05:00
The `ngFor` directive supports an optional `index` that increases from 0 to the length of the array for each iteration.
We can capture the index in a local template variable and use it in our template.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
The next example captures the index in a variable named `i`, using it to stamp out rows like "1 - Hercules Son of Zeus".
2015-11-10 13:31:46 -05:00
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgFor-3')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-10 20:07:19 -05:00
.l-sub-section
:marked
2016-01-28 19:01:39 -05:00
Learn about other special values such as `last`, `even`, and `odd` in the [NgFor API reference](../api/common/NgFor-directive.html).
2015-10-16 23:39:30 -04:00
2015-12-07 16:31:26 -05:00
<a name="star-template"></a>
<a name="structural-directive"></a>
2015-10-16 23:39:30 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2015-10-16 23:39:30 -04:00
## * and <template>
2016-01-28 19:01:39 -05:00
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.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
The `*` is a bit of syntactic sugar that makes it easier to read and write directives that modify HTML layout
2015-12-07 16:31:26 -05:00
with the help of templates.
`NgFor`, `NgIf`, and `NgSwitch` all add and remove element subtrees that are wrapped in `<template>` tags.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
With the [NgSwitch](#ngSwitch) directive we always write the `<template>` tags explicitly.
2015-10-16 23:39:30 -04:00
There isn’ t much choice; we define a different template for each switch choice
2015-12-07 16:31:26 -05:00
and let the directive render the template that matches the switch value.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
[NgFor](#ngFor) and [NgIf](#ngIf), on the other hand, each need only one template:
the *template-to-repeat* and the *template-to-include*, respectively.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
The `*` prefix syntax is a convenient way to skip the `<template>` wrapper tags and
2015-12-15 17:10:10 -05:00
focus directly on the HTML element to repeat or include.
2016-01-28 19:01:39 -05:00
Angular sees the `*` and expands the HTML into the `<template>` tags for us.
2015-12-15 17:10:10 -05:00
2015-12-13 23:10:03 -05:00
### Expanding `*ngIf`
2016-01-28 19:01:39 -05:00
We can do that expansion ourselves if we wish. Here's some code with `*ngIf`:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'Template-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Here's the equivalent with `<template>` and `ngIf`:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'Template-2')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Notice that the `*` is gone and we have a [property binding](#property-binding) to the `ngIf`
2015-11-10 13:31:46 -05:00
directive, applied in this case to the `<template>` rather than
2015-10-16 23:39:30 -04:00
the application’ s `hero-detail` component.
2015-12-07 16:31:26 -05:00
The `[hero]="currentHero"` binding remains on the child `<hero-detail>`
2016-01-28 19:01:39 -05:00
element inside the template.
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
.callout.is-critical
header Remember the brackets!
2015-11-10 13:31:46 -05:00
:marked
2015-12-13 23:10:03 -05:00
Don’ t make the mistake of writing `ngIf="currentHero"`!
2016-01-28 19:01:39 -05:00
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 would always display the `hero-detail`
2015-12-07 16:31:26 -05:00
… even when there is no `currentHero`!
2015-11-10 13:31:46 -05:00
:marked
2015-12-13 23:10:03 -05:00
### Expanding `*ngFor`
2016-01-28 19:01:39 -05:00
A similar transformation applies to `*ngFor`. We can de-sugar the syntax ourselves. First, here's an example with `*ngFor`:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'NgFor-2')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Here's the same example, slightly expanded:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'Template-3')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
And here it is, expanded further:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'Template-4')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
The `NgFor` code is a bit more complex than `NgIf` because a repeater has more moving parts to configure.
2015-12-07 16:31:26 -05:00
In this case, we have to remember the `NgForOf` directive that identifies the list.
2016-01-28 19:01:39 -05:00
Using the `*ngFor` syntax is much easier than writing out this expanded HTML ourselves.
2015-10-16 23:39:30 -04:00
2015-12-07 16:31:26 -05:00
<a id="local-vars"></a>
2015-10-16 23:39:30 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2015-10-16 23:39:30 -04:00
## Local template variables
2015-12-15 17:10:10 -05:00
2015-10-16 23:39:30 -04:00
A **local template variable** is a vehicle for moving data across element lines.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
We've seen `#hero` used to declare a local template variable several times in this chapter,
2015-12-13 23:10:03 -05:00
most prominently when writing [NgFor](#ngFor) repeaters.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
In [* and <templates>](#star-template), we learned how Angular expands
2015-12-13 23:10:03 -05:00
an `*ngFor` on a component tag into a `<template>` that wraps the component.
+makeExample('template-syntax/ts/app/app.component.html', 'Template-4')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
The hash (`#`) prefix to "hero" means that we're defining a `hero` variable.
2015-10-16 23:39:30 -04:00
.l-sub-section
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
Folks who don't like using the `#` character can use its canonical alternative,
the `var-` prefix. For example, we can declare the our `hero` variable using
either `#hero` or `var-hero`.
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
We define `hero` on the outer `<template>` element, where it becomes the current hero item
2015-12-07 16:31:26 -05:00
as Angular iterates through the list of heroes.
2015-12-15 17:10:10 -05:00
2015-12-07 16:31:26 -05:00
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.
2015-11-10 13:31:46 -05:00
2015-12-07 16:31:26 -05:00
### Referencing a local template variable
2015-12-15 17:10:10 -05:00
2015-12-07 16:31:26 -05:00
We can reference a local template variable on the same element, on a sibling element, or on
2016-01-28 19:01:39 -05:00
any child elements.
2015-10-16 23:39:30 -04:00
2015-12-07 16:31:26 -05:00
Here are two other examples of creating and consuming a local template variable:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'var-phone')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
### How a variable gets its value
The value assigned to a variable depends upon the context.
2015-11-10 13:31:46 -05:00
2015-12-07 16:31:26 -05:00
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
2015-12-27 04:38:16 -05:00
sets the `hero` variable to a hero item from the `heroes` array.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
When no directive is present, as in phone and fax examples,
Angular sets the variable's value to the element on which it was defined.
2015-12-07 16:31:26 -05:00
We defined these variables on the `input` elements.
We’ re passing those `input` element objects across to the
2016-01-28 19:01:39 -05:00
button elements, where they're used in arguments to the `call` methods in the event bindings.
2015-12-15 17:10:10 -05:00
2015-12-14 01:29:37 -05:00
### NgForm and local template variables
2016-01-28 19:01:39 -05:00
Let's look at one final example: a form, the poster child for local template variables.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
The HTML for a form can be quite involved, as we saw in the [Forms](forms.html) chapter.
2015-12-07 16:31:26 -05:00
The following is a *simplified* example — and it's not simple at all.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'var-form')
2015-12-07 16:31:26 -05:00
:marked
A local template variable, `theForm`, appears three times in this example, separated
by a large amount of HTML.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'var-form-a')
2015-12-07 16:31:26 -05:00
:marked
What is the value of `theForm`?
2015-12-15 17:10:10 -05:00
It would be the [HTMLFormElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement)
2015-12-07 16:31:26 -05:00
if Angular hadn't taken it over.
2015-12-14 01:29:37 -05:00
It's actually `ngForm`, a reference to the Angular built-in `NgForm` directive that wraps the native `HTMLFormElement`
2016-01-28 19:01:39 -05:00
and endows it with additional superpowers such as the ability to
2015-12-07 16:31:26 -05:00
track the validity of user input.
2015-10-16 23:39:30 -04:00
2015-12-15 17:10:10 -05:00
This explains how we can disable the submit button by checking `theForm.form.valid`
2015-12-07 16:31:26 -05:00
and pass an object with rich information to the parent component's `onSubmit` method.
2015-11-10 13:31:46 -05:00
2015-12-07 16:31:26 -05:00
<a id="inputs-outputs"></a>
.l-main-section
:marked
2016-01-28 19:01:39 -05:00
## Input and output properties
So far, we’ ve focused mainly on binding to component members within template expressions and statements
that appear on the *right side of the binding declaration*.
A member in that position is a data binding **source**.
This section concentrates on binding to **targets**, which are directive
properties on the *left side of the binding declaration*.
These directive properties must be declared as **inputs** or **outputs**.
2016-01-10 20:07:19 -05:00
.alert.is-important
2016-01-28 19:01:39 -05:00
:markdown
Remember: All **components** are **directives**.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
:marked
2015-10-16 23:39:30 -04:00
.l-sub-section
2015-11-10 13:31:46 -05:00
:marked
2015-12-07 16:31:26 -05:00
We're drawing a sharp distinction between a data binding **target** and a data binding **source**.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
The *target* of a binding is to the *left* of the `=`.
The *source* is on the *right* of the `=`.
2016-01-10 20:07:19 -05:00
The *target* of a binding is the property or event inside the binding punctuation: `[]`, `()` or `[()]`.
2016-01-28 19:01:39 -05:00
The *source* is either inside quotes (`" "`) or within an interpolation (`{}`).
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
Every member of a **source** directive is automatically available for binding.
We don't have to do anything special to access a directive member in a template expression or statement.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
We have *limited* access to members of a **target** directive.
2016-01-10 20:07:19 -05:00
We can only bind to properties that are explicitly identified as *inputs* and *outputs*.
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
In the following example, `iconUrl` and `onSave` are members of a component
that are referenced within quoted syntax to the right of the `=`.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'io-1')(format=".")
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
They are *neither inputs nor outputs* of the component. They are data sources for their bindings.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
Now look at `HeroDetailComponent` when it is the **target of a binding**.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'io-2')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
Both `HeroDetailComponent.hero` and `HeroDetailComponent.deleted` are on the **left side** of binding declarations.
`HeroDetailComponent.hero` is inside brackets; it is the target of a property binding.
`HeroDetailComponent.deleted` is inside parentheses; it is the target of an event binding.
2016-01-10 20:07:19 -05:00
### Declaring input and output properties
Target properties must be explicitly marked as inputs or outputs.
2016-01-28 19:01:39 -05:00
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.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/hero-detail.component.ts', 'input-output-1')(format=".")
2015-12-07 16:31:26 -05:00
:marked
.l-sub-section
:marked
2016-01-28 19:01:39 -05:00
Alternatively, we can identify members in the `inputs` and `outputs` arrays
of the directive metadata, as in this example:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/hero-detail.component.ts', 'input-output-2')(format=".")
2015-12-07 16:31:26 -05:00
<br>
:marked
2016-01-28 19:01:39 -05:00
We can specify an input/output property either with a decorator or in a metadata array.
2015-12-14 01:29:37 -05:00
Don't do both!
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
### Input or output?
2016-01-10 20:07:19 -05:00
*Input* properties usually receive data values.
2016-01-28 19:01:39 -05:00
*Output* properties expose event producers, such as `EventEmitter` objects.
The terms _input_ and _output_ reflect the perspective of the target directive.
`HeroDetailComponent.hero` is an **input** property from the perspective of `HeroDetailComponent`
because data flows *into* that property from a template binding expression.
`HeroDetailComponent.deleted` is an **output** property from the perspective of `HeroDetailComponent`
2016-01-10 20:07:19 -05:00
because events stream *out* of that property and toward the handler in a template binding statement.
2016-01-28 19:01:39 -05:00
2015-12-07 16:31:26 -05:00
### Aliasing input/output properties
2015-12-15 17:10:10 -05:00
2016-01-10 20:07:19 -05:00
Sometimes we want the public name of an input/output property to be different from the internal name.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
This is frequently the case with [attribute directives](attribute-directives.html).
2015-12-07 16:31:26 -05:00
Directive consumers expect to bind to the name of the directive.
2016-01-19 02:54:27 -05:00
For example, when we apply a directive with a `myClick` selector to a `<div>` tag,
we expect to bind to an event property that is also called `myClick`.
+makeExample('template-syntax/ts/app/app.component.html', 'my-click')(format=".")
:marked
However, the directive name is often a poor choice for the the name of a property within the directive class.
The directive name rarely describes what the property does.
The `myClick` directive name is not a good name for a property that emits click messages.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
Fortunately, we can have a public name for the property that meets conventional expectations,
2016-01-19 02:54:27 -05:00
while using a different name internally.
2016-01-28 19:01:39 -05:00
In the example immediately above, we are actually binding *through the* `myClick` *alias* to
2016-01-19 02:54:27 -05:00
the directive's own `clicks` property.
2016-01-28 19:01:39 -05:00
We can specify the alias for the property name by passing it into the input/output decorator like this:
2016-01-19 02:54:27 -05:00
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/my-click.directive.ts', 'my-click-output-1')(format=".")
2016-01-10 20:07:19 -05:00
:marked
2016-01-19 02:54:27 -05:00
2016-01-28 19:01:39 -05:00
2015-12-07 16:31:26 -05:00
.l-sub-section
:marked
2016-01-19 02:54:27 -05:00
We can also alias property names in the `inputs` and `outputs` arrays.
2016-01-28 19:01:39 -05:00
We write a colon-delimited (`:`) string with
2016-01-19 02:54:27 -05:00
the directive property name on the *left* and the public alias on the *right*:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/my-click.directive.ts', 'my-click-output-2')(format=".")
2015-12-15 17:10:10 -05:00
2015-12-07 16:31:26 -05:00
<a id="expression-operators"></a>
2015-10-16 23:39:30 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
## Template expression operators
The template expression language employs a subset of JavaScript syntax supplemented with a few special operators
for specific scenarios. We'll cover two of these operators: _pipe_ and _Elvis_.
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
<a id="pipe"></a>
2016-01-28 19:01:39 -05:00
### The pipe operator ( | )
The result of an expression might require some transformation before we’ re ready to use it in a binding. For example, we might want to display a number as a currency, force text to uppercase, or filter a list and sort it.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
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.
2016-01-28 19:01:39 -05:00
They're easy to apply within template expressions, using the **pipe operator (`|`)**:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'pipes-1')(format=".")
2015-11-10 13:31:46 -05:00
: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.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
We can chain expressions through multiple pipes:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'pipes-2')(format=".")
2015-12-07 16:31:26 -05:00
:marked
And we can configure them too:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'pipes-3')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
The `json` pipe is particularly helpful for debugging our bindings:
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'pipes-json')(format=".")
2015-11-10 13:31:46 -05:00
:marked
2015-10-16 23:39:30 -04:00
<a id="elvis"></a>
2016-01-28 19:01:39 -05:00
### The Elvis operator ( ?. ) and null property paths
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
The Angular **Elvis operator (`?.`)** is a fluent and convenient way to guard against null and undefined values in property paths.
2015-12-07 16:31:26 -05:00
Here it is, protecting against a view render failure if the `currentHero` is null.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-2')(format=".")
2015-11-10 13:31:46 -05:00
:marked
2015-10-16 23:39:30 -04:00
Let’ s elaborate on the problem and this particular solution.
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
What happens when the following data bound `title` property is null?
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-1')(format=".")
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
The view still renders but the displayed value is blank; we see only "The title is" with nothing after it.
2015-12-07 16:31:26 -05:00
That is reasonable behavior. At least the app doesn't crash.
2016-01-28 19:01:39 -05:00
Suppose the template expression involves a property path, as in this next example
2015-12-07 16:31:26 -05:00
where we’ re displaying the `firstName` of a null hero.
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
code-example(format="" language="html").
2015-12-07 16:31:26 -05:00
The null hero's name is {{nullHero.firstName}}
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
JavaScript throws a null reference error, and so does Angular:
2015-10-16 23:39:30 -04:00
code-example(format="" language="html").
TypeError: Cannot read property 'firstName' of null in [null]
2015-11-10 13:31:46 -05:00
:marked
2015-12-07 16:31:26 -05:00
Worse, the *entire view disappears*.
2015-10-16 23:39:30 -04:00
2015-12-07 16:31:26 -05:00
We could claim that this is reasonable behavior if we believed 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.
2015-12-07 16:31:26 -05:00
Throwing an exception is the right thing to do.
2015-11-10 13:31:46 -05:00
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.
2015-12-15 17:10:10 -05:00
2016-01-28 19:01:39 -05:00
While we wait for data, the view should render without complaint, and
2015-12-07 16:31:26 -05:00
the null property path should display as blank just as the `title` property does.
2015-11-10 13:31:46 -05:00
2015-10-16 23:39:30 -04:00
Unfortunately, our app crashes when the `currentHero` is null.
2015-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
We could code around that problem with [NgIf](#ngIf).
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-4')(format=".")
2015-11-10 13:31:46 -05:00
:marked
2015-12-07 16:31:26 -05:00
Or we could try to chain parts of the property path with `&&`, knowing that the expression bails out
when it encounters the first null.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-5')(format=".")
2015-12-07 16:31:26 -05:00
:marked
2016-01-28 19:01:39 -05:00
These approaches have merit but can be 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-11-10 13:31:46 -05:00
2016-01-28 19:01:39 -05:00
The Angular Elvis operator (`?.`) is a more fluent and convenient way to guard against nulls in property paths.
2015-12-15 17:10:10 -05:00
The expression bails out when it hits the first null value.
2016-01-28 19:01:39 -05:00
The display is blank, but the app keeps rolling without errors.
2015-12-13 23:10:03 -05:00
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-6')(format=".")
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
It works perfectly with long property paths such as `a?.b?.c?.d`.
2015-10-16 23:39:30 -04:00
.l-main-section
2015-11-10 13:31:46 -05:00
:marked
2016-01-28 19:01:39 -05:00
## Summary
We’ ve completed our survey of template syntax. Now it's time to put that knowledge to work as we write our own components and directives.