docs(template-syntax): sample/devmode fix + text updates

closes #692
This commit is contained in:
Ward Bell 2016-01-10 17:07:19 -08:00
parent 3e18dd1203
commit 0f5294e32c
4 changed files with 272 additions and 97 deletions

View File

@ -255,7 +255,10 @@ button</button>
<div>
<!-- #docregion event-binding-3 -->
<!-- `myClick` is an event on the custom `MyClickDirective` -->
<!-- #docregion my-click -->
<div myClick (myClick)="clickity=$event">click with myClick</div>
<!-- #enddocregion my-click -->
<!-- #enddocregion event-binding-3 -->
{{clickity}}
</div>
@ -382,8 +385,8 @@ After setClasses(), the classes are "{{classDiv.className}}"
This div is italic, normal weight, and x-large
</div>
<!-- #enddocregion NgStyle-3 -->
<div [ngStyle]="setStyles2()" #styleDiv>
After setStyles2(), the styles are "{{getStyles(styleDiv)}}"
<div [ngStyle]="setStyles2()" #styleDiv2>
After setStyles2(), the styles are "{{getStyles(styleDiv2)}}"
</div>
<!-- not used in chapter -->
@ -445,7 +448,7 @@ After setClasses(), the classes are "{{classDiv.className}}"
<div class="toe">
<div *ngIf="!toeChoice">Pick a toe</div>
<div *ngIf="toeChoice">You picked
<!-- #docregion NgSwitch -->
<!-- #docregion NgSwitch -->
<span [ngSwitch]="toeChoice">
<template [ngSwitchWhen]="'Eenie'">Eenie</template>
<template [ngSwitchWhen]="'Meanie'">Meanie</template>
@ -453,7 +456,7 @@ After setClasses(), the classes are "{{classDiv.className}}"
<template [ngSwitchWhen]="'Moe'">Moe</template>
<template ngSwitchDefault>Other</template>
</span>
<!-- #enddocregion NgSwitch -->
<!-- #enddocregion NgSwitch -->
</div>
</div>
@ -477,8 +480,8 @@ After setClasses(), the classes are "{{classDiv.className}}"
<br>
<div class="box">
<!-- Ex: 1 - Hercules Son of Zeus -->
<!-- #docregion NgFor-3 -->
<!-- Ex: 1 - Hercules Son of Zeus -->
<div *ngFor="#hero of heroes, #i=index">{{i + 1}} - {{hero.fullName}}</div>
<!-- #enddocregion NgFor-3 -->
</div>

View File

@ -1,3 +1,5 @@
//#docplaster
import {Component} from 'angular2/core';
import {NgForm} from 'angular2/common';
@ -37,6 +39,11 @@ export class AppComponent {
currentHero = Hero.MockHeroes[0];
// DevMode memoization fields
private _priorClasses:{};
private _priorStyles:{};
private _priorStyles2:{};
getStyles(el:Element){
let styles = window.getComputedStyle(el);
let showStyles = {};
@ -100,36 +107,61 @@ export class AppComponent {
// #docregion setClasses
setClasses() {
return {
let classes = {
saveable: this.canSave, // true
modified: !this.isUnchanged, // false
special: this.isSpecial, // true
}
// #enddocregion setClasses
// compensate for DevMode (sigh)
if (JSON.stringify(classes) === JSON.stringify(this._priorClasses)){
return this._priorClasses;
}
this._priorClasses = classes;
// #docregion setClasses
return classes;
}
// #enddocregion setClasses
// #docregion setStyles
setStyles() {
return {
let styles = {
// CSS property names
'font-style': this.canSave ? 'italic' : 'normal', // italic
'font-weight': !this.isUnchanged ? 'bold' : 'normal', // normal
'font-size': this.isSpecial ? 'x-large': 'smaller', // larger
}
// #enddocregion setStyles
// compensate for DevMode (sigh)
if (JSON.stringify(styles) === JSON.stringify(this._priorStyles)){
return this._priorStyles;
}
this._priorStyles = styles;
// #docregion setStyles
return styles;
}
// #enddocregion setStyles
// #docregion setStyles2
setStyles2() {
return {
let styles = {
// camelCase style properties work too
fontStyle: this.canSave ? 'italic' : 'normal', // italic
fontWeight: !this.isUnchanged ? 'bold' : 'normal', // normal
fontSize: this.isSpecial ? 'x-large': 'smaller', // larger
}
// #enddocregion setStyles2
// compensate for DevMode (sigh)
if (JSON.stringify(styles) === JSON.stringify(this._priorStyles2)){
return this._priorStyles2;
}
this._priorStyles2 = styles;
// #docregion setStyles2
return styles;
}
// #enddocregion setStyles2
toeChoice = '';
toeChooser(picker:HTMLFieldSetElement){
let choices = picker.children;

View File

@ -1,7 +1,7 @@
// #docplaster
import {Directive, Output, ElementRef, EventEmitter} from 'angular2/core';
@Directive({selector:'[mClick]'})
@Directive({selector:'[myClick]'})
export class MyClickDirective {
// #docregion my-click-output-1
@Output('myClick') clicks = new EventEmitter<string>();

View File

@ -16,6 +16,8 @@ include ../../../../_includes/_util-fns
>[Template expressions](#template-expressions)
>[Template statements](#template-statements)
>[Binding syntax](#binding-syntax)
>[Property Binding](#property-binding)
@ -82,67 +84,156 @@ include ../../../../_includes/_util-fns
But it is not literally true. Interpolation is actually a special syntax that Angular converts into a
[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.
But before we explore that assertion, well take a closer look at template expressions and statements.
<a id="template-expressions"></a>
.l-main-section
:marked
## Template Expressions
We saw a template expression within the interpolation braces.
Well see template expressions again in [Property Bindings](#property-binding) (`[property]="expression"`) and
[Event Bindings](#event-binding) (`(event)="expression"`).
A template **expression** produces a value.
Angular executes the expression and assigns it to property of a binding target such
as an HTML element, a component, or a directive.
We put a template expression within the interpolation braces when we wrote `{{1 + 1}}`.
Well see template expressions again in [Property Bindings](#property-binding) ,
appearing in quotes to the right of the (=) symbol as in `[property]="expression"`.
A template expression is a JavaScript-like expression. Many JavaScript expressions are legal template expressions but not all and there are a few language extensions. Notable differences include:
* 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.
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:
* assignment (`=`)
* the `new` operator
* chaining expressions with `;` or `,`
* increment and decrement operators, `++` and `--`.
Other notable differences from JavaScript syntax include:
* no support for the bit-wise operators, `|` and `&`
* new [template expression operators](#expression-operators), such as `|` and `?.`
<a id="expression-context"></a>
### Expression Context
Perhaps more surprising, we cannot refer to anything in the global namespace.
We cant refer to `window` or `document`. We cant call `console.log`.
We cant refer to `window` or `document`. We cant call `console.log` or `Math.max`.
We are restricted to referencing members of the expression context.
The *expression context* is typically the **component instance**, the source of binding values.
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.
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, <code>{{ }}</code>.,
we know that it is a property of a parent component.
When we see `[disabled]="isUnchanged"` or `(click)="onCancel()”`,
we know we are referring to that component's `isUnchanged` property and `onCancel` method respectively.
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.
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 alternative context object.
A [local template variable](#local-vars) is one such supplemental context object;
well discuss that option below.
<a id="no-side-effects"></a>
### Expression Guidelines
Template expressions can make or break an application.
Please follow these guidelines unless you have an exceptionally good reason to break them
in specific circumstances that you thoroughly understand.
#### No visible side-effects
Another is the **`$event`** variable that contains information about an event raised on an element;
well talk about that when we consider [Event Bindings](#event-binding).
A template expression should have ***no visible side-effects***.
We're not allowed to change any application state other than the value of the
target property.
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.
#### Finish fast
Angular executes template expressions more often than we might think.
Expressions should finish quickly or the user experience may drag, especially on slower devices.
#### Keep them simple
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.
#### Idempotent Expressions
An [idempotent](https://en.wikipedia.org/wiki/Idempotence) expression is ideal because
it is free of side-effects and improves Angular's change detection performance.
In Angular terms, an idempotent expression always returns *exactly the same thing* until
one of its dependent values changes.
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`),
it returns the same object *reference* when called twice in a row.
<a id="template-statements"></a>
.l-main-section
:marked
## Template Statements
A template **statement** responds to an ***event*** raised by a binding target
such as an element, component, or directive.
Well see template statements in [Event Bindings](#event-binding),
appearing in quotes to the right of the (=) symbol as in `(event)="statement"`.
A template statement *has a side-effect*.
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
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.
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
Now that we have a feel for template expressions, were ready to learn about the varieties of data binding syntax beyond Interpolation.
Angular template statements are also written in a language that looks like JavaScript.
The template statement parser is different than the template expression parser and
specifically supports both assignment (=) and chaining expressions with semicolons (;) and commas (,).
However, certain JavaScript syntax is not allowed:
* the `new` operator
* increment and decrement operators, `++` and `--`
* bit-wise operators, `|` and `&`
* the [template expression operators](#expression-operators)
As with expressions, we cannot refer to anything in the global namespace.
We cant refer to `window` or `document`. We cant call `console.log` or `Math.max`.
We are restricted to referencing members of the statement context.
The **statement context** is typically the **component instance** to which we are binding an event.
The *onSave* in `(click)="onSave()"` is sure to be a method of the data-bound component instance.
The statement context may include an object other than the component.
A [local template variable](#local-vars) is one such alternative context object.
We'll frequently see the reserved `$event` symbol in event binding statements,
representing the "message" or "payload" of the raised event.
.l-sub-section
:marked
Although we can write quite complex template statements, we strongly discourage that practice.
Most readers frown on JavaScript in the HTML.
A method call or simple property assignment should be the norm.
:marked
Now that we have a feel for template expressions and statements,
were ready to learn about the varieties of data binding syntax beyond Interpolation.
.l-main-section
:marked
<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,
Data binding is a mechanism for coordinating what users see with application data values.
While we could push values to and pull values from HTML,
the application is easier to write, read, and maintain if we turn these chores over to a binding framework.
We simply declare bindings between the HTML and the data properties and let the framework do the work.
We simply declare bindings between binding sources and target HTML elements and let the framework do the work.
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.
We can group all bindings into three categories by the direction in which data flows. Each category has its distinctive syntax:
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
@ -165,8 +256,8 @@ table
td One way<br>from view target<br>to data source
td
code-example(format="" ).
(target) = "expression"
on-target = "expression"
(target) = "statement"
on-target = "statement"
td Event
tr
td Two way
@ -176,10 +267,8 @@ table
bindon-target = "expression"
td Two-way
:marked
**Template expressions must be surrounded in quotes**
except for interpolation expressions which must not be quoted.
All binding types except interpolation have a **target name** to the left of the equal sign, either surrounded by punctuation (`[]`, `()`) or preceded by a prefix (`bind-`, `on-`, `bindon-`).
Binding types other than 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.
@ -187,8 +276,8 @@ table
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”.
*Well it is HTML Plus*.
But its also significantly different than the HTML were used to.
We really need a new mental model.
@ -214,7 +303,7 @@ table
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.
We are setting the *properties* of DOM elements, components, and directives.
.l-sub-section
:marked
@ -336,7 +425,8 @@ table
.l-main-section
:marked
## 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.
We write a template **Property Binding** when we want to set a property of a view element to the value of
a [template expression](#template-expressions).
The most common Property Binding sets an element property to a component property value as when
we bind the source property of an image element to the components `heroImageUrl` property.
@ -352,8 +442,26 @@ table
for parent and child components to communicate)
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-4')(format=".")
:marked
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.
### One-way *in*
People often describe property binding as *one way data binding* because it flows a value in one direction,
from a components data property into a target element property.
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.
If the element raises events we can listen to them with an [event binding](#event-binding).
If we must read a target element property or call one of its methods,
we'll need a different technique.
See the API reference for
[viewChild](../api/core/ViewChild-var.html) and
[contentChild](../api/core/ContentChild-var.html).
:marked
### Binding Target
A name between enclosing square brackets identifies the target property. The target property in this example is the image elements `src` property.
@ -527,11 +635,12 @@ code-example(format="", language="html").
keystrokes, mouse movements, clicks and touches.
We declare our interest in user actions through Angular Event Binding.
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 buttons click event and calls the component's `onSave()` method:
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-1')(format=".")
:marked
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.
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-1')(format=".")
@ -546,11 +655,11 @@ code-example(format="", language="html").
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
### $event and event handling statements
In an Event Binding, Angular sets up an event handler for the target event.
When the event is raised, the handler executes the template expression.
The template expression typically involves a receiver that wants to do something
When the event is raised, the handler executes the template statement.
The template statement 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.
@ -565,7 +674,7 @@ code-example(format="", language="html").
+makeExample('template-syntax/ts/app/app.component.html', 'without-NgModel')(format=".")
:marked
Were binding the input box `value` to a `firstName` property and were listening for changes by binding to the input boxs `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`.
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`.
We must follow the `$event.target.value` path to get the changed text so we can update the `firstName`
@ -578,19 +687,19 @@ code-example(format="", language="html").
Now imagine a parent component that listens for that event with an Event Binding.
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-to-component')(format=".")
:marked
The event binding surfaces the *hero-to-delete* emitted by `HeroDetail` to the expression via the `$event` variable.
The event binding surfaces the *hero-to-delete* emitted by `HeroDetail` to the statement via the `$event` variable.
We pass it along to the parent `onHeroDeleted()` method.
That method presumably knows how to delete the hero.
Evaluation of an Event Binding template expression may have side-effects as this one clearly does.
They are not just OK (unlike in property bindings); they are expected.
Evaluation of this Event Binding template statement has a side-effect. It deletes a hero.
Side-effects are not just OK; they are expected.
The expression could update the model thereby triggering other changes that percolate through the system, changes that
The statement could update the model thereby triggering other changes that percolate through the system, changes that
are ultimately displayed in this view and other views.
The event processing may result in queries and saves to a remote server. It's all good.
### Event bubbling and propagation
Angular invokes the event-handling expression if the event is raised by the current element or one of its child elements.
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” events up their ancestor tree of DOM elements until an event handler along the way prevents further propagation.
@ -600,16 +709,16 @@ code-example(format="", language="html").
`EventEmitter` events dont bubble.
:marked
The result of an Event Binding expression determines if
The result of an Event Binding statement 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.
Event propagation stops if the binding expression returns a falsey value (as does a method with no return value).
Event propagation stops if the binding statement returns a falsey value (as does a method with no return value).
Clicking the button in this next example triggers a save;
the click doesn't make it to the outer `<div>` so it's save is not called:
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-no-propagation')(format=".")
:marked
Propagation continues if the expression returns a truthy value. The click is heard both by the button
Propagation continues if the statement returns a truthy value. The click is heard both by the button
and the outer `<div>`, causing a double save:
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-propagation')(format=".")
@ -622,6 +731,12 @@ code-example(format="", language="html").
The `NgModel` directive serves that purpose as seen in this example:
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-1')(format=".")
.callout.is-important
header
: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*.
:marked
If we prefer the “canonical” prefix form to the punctuation form, we can write
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-2')(format=".")
@ -844,6 +959,9 @@ figure.image-display
+makeExample('template-syntax/ts/app/app.component.html', 'NgFor-3')(format=".")
:marked
.l-sub-section
:marked
Learn about other special values such as `last`, `even` and `odd` in the [API](../api/common/NgFor-directive.html) guide.
<a name="star-template"></a>
<a name="structural-directive"></a>
@ -980,30 +1098,33 @@ figure.image-display
:marked
## Input and Output Properties
We can only bind to **target directive** properties that are either **inputs** or **outputs**.
.alert.is-important
:marked
A *component is a directive*. We use the terms "directive" and "component" interchangeably.
.l-sub-section
:marked
We're drawing a sharp distinction between a data binding **target** and a data binding **source**.
The target is to the *left* of the (=) in a binding expression.
The source is on the *right* of the (=).
The *target* of a binding is to the *left* of the (=).
The *source* is on the *right* of the (=).
The *target* of a binding is the property or event inside the binding punctuation: `[]`, `()` or `[()]`.
The *source* is either inside quotes (") or within an interpolation (`{}`).
Every member of a **source** directive (typically a component) is automatically available for binding.
We don't have to do anything special to access a component member in the quoted template expression
to the right of the (=).
Every member of a **source** directive or component is automatically available for binding.
We don't have to do anything special to access a component member in a template expression or statement.
We have *limited* access to members of a **target** directive (typically a component).
We can only bind to *input* and *output* properties of target components to the left of the (=).
Also remember that a *component is a directive*.
In this section, we use the terms "directive" and "component" interchangeably.
We have *limited* access to members of a **target** directive or component.
We can only bind to properties that are explicitly identified as *inputs* and *outputs*.
:marked
In this chapter weve focused mainly on binding to component members within template expressions
on the *right side of the binding declaration*.
A member in that position is a binding “data source”. It's not a target for binding.
In this chapter weve 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 binding “data source”.
In the following example, `iconUrl` and `onSave` are members of the `AppComponent`
referenced within template expressions to the *right* of the (=).
referenced within quoted syntax to the right of the (=).
+makeExample('template-syntax/ts/app/app.component.html', 'io-1')(format=".")
:marked
They are *neither inputs nor outputs* of `AppComponent`. They are data sources for their bindings.
@ -1011,16 +1132,13 @@ figure.image-display
Now look at the `HeroDetailComponent` when it is the **target of a binding**.
+makeExample('template-syntax/ts/app/app.component.html', 'io-2')(format=".")
:marked
Both `HeroDetail.hero` and `HeroDetail.deleted` are on the **left side** of binding expressions.
`HeroDetail.hero` is the target of a Property Binding. `HeroDetail.deleted` is the target of an Event Binding.
**Data flow *into* the `HeroDetail.hero` target property** from the template expression.
Therefore `HeroDetail.hero` is an ***input*** property from the perspective of `HeroDetail`.
**Events stream *out* of the `HeroDetail.deleted` target property** and toward the receiver within the template expression.
Therefore `HeroDetail.deleted` is an ***output*** property from the perspective of `HeroDetail`.
Both `HeroDetail.hero` and `HeroDetail.deleted` are on the **left side** of binding declarations.
`HeroDetail.hero` is inside brackets; it is the target of a Property Binding.
`HeroDetail.deleted` is inside parentheses; it is the target of an Event Binding.
### Declaring input and output properties
Target properties must be explicitly marked as inputs or outputs.
When we peek inside `HeroDetailComponent` we see that these properties are marked
with decorators as input and output properties.
+makeExample('template-syntax/ts/app/hero-detail.component.ts', 'input-output-1')(format=".")
@ -1035,9 +1153,22 @@ figure.image-display
We can specify an input/output property with a decorator or in one the metadata arrays.
Don't do both!
:marked
### Input or Output?
*Input* properties usually receive data values.
*Output* properties expose event producers (e.g, an `EventEmitter`).
The terms "input" and "output" reflect the perspective of the target directive.
`HeroDetail.hero` is an ***input*** property from the perspective of `HeroDetailComponent`
because data flow *into* that property from a template binding expression.
`HeroDetail.deleted` is an ***output*** property from the perspective of `HeroDetailComponent`
because events stream *out* of that property and toward the handler in a template binding statement.
### Aliasing input/output properties
Sometimes we want the public name of the property to be different from the internal name.
Sometimes we want the public name of an input/output property to be different from the internal name.
This is frequently the case with [Attribute Directives](attribute-directives.html).
Directive consumers expect to bind to the name of the directive.
@ -1045,14 +1176,23 @@ figure.image-display
The directive name is often a poor choice for the the internal property name
because it rarely describes what the property does.
The corresponding `MyClickDirective` internal property is called `clicks`.
`myClick` is not a good name for a property that emits click events.
Fortunately, we can alias the internal name to meet the conventional needs of the directive's consumer.
We alias in decorator syntax like this:
Fortunately, we can have a public name for the property that meets conventional expectations
and use a different name internally
by providing a public alias for the internal property name in the decorator like this:
+makeExample('template-syntax/ts/app/my-click.directive.ts', 'my-click-output-1')(format=".")
:marked
Now the directive name, `myClick`, is the public facing property name to which we can bind
+makeExample('template-syntax/ts/app/app.component.html', 'my-click')(format=".")
:marked
while inside the directive, the property is known as `clicks`.
With aliasing we please both the directive consumer and the directive author.
.l-sub-section
:marked
The equivalent aliasing with the `outputs` array requires a colon-delimited string with
We can alias property names in the `inputs` and `outputs` arrays as well.
We write a colon-delimited string with
the internal property name on the left and the public name on the right:
+makeExample('template-syntax/ts/app/my-click.directive.ts', 'my-click-output-2')(format=".")