parent
a89e57f1b1
commit
933433ceea
@ -35,7 +35,7 @@ include ../../../../_includes/_util-fns
|
|||||||
>[Input and Output Properties](#inputs-outputs)
|
>[Input and Output Properties](#inputs-outputs)
|
||||||
|
|
||||||
>[Template Expression Operators](#expression-operators)
|
>[Template Expression Operators](#expression-operators)
|
||||||
|
|
||||||
[Live Example](/resources/live-examples/template-syntax/ts/plnkr.html).
|
[Live Example](/resources/live-examples/template-syntax/ts/plnkr.html).
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
@ -118,7 +118,7 @@ include ../../../../_includes/_util-fns
|
|||||||
The component itself is usually the expression *context* in which case
|
The component itself is usually the expression *context* in which case
|
||||||
the template expression usually references that component.
|
the template expression usually references that component.
|
||||||
The expression context may include an object other than the component.
|
The expression context may include an object other than the component.
|
||||||
|
|
||||||
A [local template variable](#local-vars) is one such supplemental context object;
|
A [local template variable](#local-vars) is one such supplemental context object;
|
||||||
we’ll discuss that option below.
|
we’ll discuss that option below.
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ table
|
|||||||
But it’s also significantly different than the HTML we’re used to.
|
But it’s also significantly different than the HTML we’re used to.
|
||||||
We really need a new mental model.
|
We really need a new mental model.
|
||||||
|
|
||||||
In the normal course of HTML development, we create a visual structure with HTML elements and
|
In the normal course of HTML development, we create a visual structure with HTML elements and
|
||||||
we modify those elements by setting element attributes with string constants.
|
we modify those elements by setting element attributes with string constants.
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'img+button')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'img+button')(format=".")
|
||||||
:marked
|
:marked
|
||||||
@ -330,10 +330,6 @@ table
|
|||||||
+makeExample('template-syntax/ts/app/app.component.html', 'style-binding-syntax-1')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'style-binding-syntax-1')(format=".")
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
.l-sub-section
|
|
||||||
:marked
|
|
||||||
According to this rule, we should write `[inner-h-t-m-l]` to access the element’s `innerHTML` property.
|
|
||||||
Fortunately, the Angular template parser recognizes `inner-html` as an acceptable alias for `innerHTML`.
|
|
||||||
:marked
|
:marked
|
||||||
Let’s descend from the architectural clouds and look at each of these binding types in concrete detail.
|
Let’s descend from the architectural clouds and look at each of these binding types in concrete detail.
|
||||||
|
|
||||||
@ -407,7 +403,7 @@ table
|
|||||||
|
|
||||||
### Property Binding or Interpolation?
|
### Property Binding or Interpolation?
|
||||||
We often have a choice between Interpolation and Property Binding. The following binding pairs do the same thing
|
We often have a choice between Interpolation and Property Binding. The following binding pairs do the same thing
|
||||||
|
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-vs-interpolation')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'property-binding-vs-interpolation')(format=".")
|
||||||
:marked
|
:marked
|
||||||
Interpolation is actually a convenient alternative for Property Binding in many cases.
|
Interpolation is actually a convenient alternative for Property Binding in many cases.
|
||||||
@ -452,7 +448,7 @@ code-example(format="", language="html").
|
|||||||
Can't bind to 'colspan' since it isn't a known native property
|
Can't bind to 'colspan' since it isn't a known native property
|
||||||
:marked
|
:marked
|
||||||
As the message says, the `<td>` element does not have a `colspan` property.
|
As the message says, the `<td>` element does not have a `colspan` property.
|
||||||
It has the "colspan" *attribute* but
|
It has the "colspan" *attribute* but
|
||||||
interpolation and property binding can only set properties, not attributes.
|
interpolation and property binding can only set properties, not attributes.
|
||||||
|
|
||||||
We need an Attribute Binding to create and bind to such attributes.
|
We need an Attribute Binding to create and bind to such attributes.
|
||||||
@ -466,7 +462,7 @@ code-example(format="", language="html").
|
|||||||
:marked
|
:marked
|
||||||
Here's how the table renders:
|
Here's how the table renders:
|
||||||
<table border="1px">
|
<table border="1px">
|
||||||
<tr><td colspan="2">One-Two</td></tr>
|
<tr><td colspan="2">One-Two</td></tr>
|
||||||
<tr><td>Five</td><td>Six</td></tr>
|
<tr><td>Five</td><td>Six</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@ -475,11 +471,11 @@ code-example(format="", language="html").
|
|||||||
+makeExample('template-syntax/ts/app/app.component.html', 'attrib-binding-aria')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'attrib-binding-aria')(format=".")
|
||||||
:marked
|
:marked
|
||||||
### Class Binding
|
### Class Binding
|
||||||
|
|
||||||
We can add and remove CSS class names from an element’s `class` attribute with the **Class Binding**.
|
We can add and remove CSS class names from an element’s `class` attribute with the **Class Binding**.
|
||||||
|
|
||||||
Class Binding syntax resembles Property Binding.
|
Class Binding syntax resembles Property Binding.
|
||||||
Instead of an element property between brackets, we start with the keyword `class` followed
|
Instead of an element property between brackets, we start with the keyword `class` followed
|
||||||
by the name of a CSS class: `[class.class-name]`.
|
by the name of a CSS class: `[class.class-name]`.
|
||||||
|
|
||||||
In the following examples we see how to add and remove the application's "special" class
|
In the following examples we see how to add and remove the application's "special" class
|
||||||
@ -490,7 +486,7 @@ code-example(format="", language="html").
|
|||||||
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-2')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-2')(format=".")
|
||||||
:marked
|
:marked
|
||||||
Finally, we bind to a specific class name.
|
Finally, we bind to a specific class name.
|
||||||
Angular adds the class when the template expression evaluates to something truthy and
|
Angular adds the class when the template expression evaluates to something truthy and
|
||||||
removes the class name when the expression is falsey.
|
removes the class name when the expression is falsey.
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-3')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'class-binding-3')(format=".")
|
||||||
|
|
||||||
@ -504,8 +500,8 @@ code-example(format="", language="html").
|
|||||||
|
|
||||||
We can set inline styles with a **Style Binding**.
|
We can set inline styles with a **Style Binding**.
|
||||||
|
|
||||||
Style Binding syntax resembles Property Binding.
|
Style Binding syntax resembles Property Binding.
|
||||||
Instead of an element property between brackets, we start with the key word `style`
|
Instead of an element property between brackets, we start with the key word `style`
|
||||||
followed by the name of a CSS style property: `[style.style-property]`.
|
followed by the name of a CSS style property: `[style.style-property]`.
|
||||||
|
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'style-binding-1')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'style-binding-1')(format=".")
|
||||||
@ -547,7 +543,7 @@ code-example(format="", language="html").
|
|||||||
of a known directive as it does in the following example:
|
of a known directive as it does in the following example:
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-3')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-3')(format=".")
|
||||||
:marked
|
:marked
|
||||||
If the name fails to match an element event or an output property of a known directive,
|
If the name fails to match an element event or an output property of a known directive,
|
||||||
Angular reports an “unknown directive” error.
|
Angular reports an “unknown directive” error.
|
||||||
|
|
||||||
### $event and event handling expressions
|
### $event and event handling expressions
|
||||||
@ -568,16 +564,16 @@ code-example(format="", language="html").
|
|||||||
Consider this example:
|
Consider this example:
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'without-NgModel')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'without-NgModel')(format=".")
|
||||||
:marked
|
:marked
|
||||||
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.
|
We’re binding the input box `value` to a `firstName` property and we’re listening for changes by binding to the input box’s `input` event.
|
||||||
When the user makes changes, the `input` event is raised, and the binding executes the expression within a context that includes the DOM event object, `$event`.
|
When the user makes changes, the `input` event is raised, and the binding executes the expression within a context that includes the DOM event object, `$event`.
|
||||||
|
|
||||||
We must follow the `$event.target.value` path to get the changed text so we can update the `firstName`
|
We must follow the `$event.target.value` path to get the changed text so we can update the `firstName`
|
||||||
|
|
||||||
If the event belongs to a directive (remember: components are directives), `$event` has whatever shape the directive chose to produce.
|
If the event belongs to a directive (remember: components are directives), `$event` has whatever shape the directive chose to produce.
|
||||||
Consider a `HeroDetailComponent` that produces `deleted` events with an `EventEmitter`.
|
Consider a `HeroDetailComponent` that produces `deleted` events with an `EventEmitter`.
|
||||||
+makeExample('template-syntax/ts/app/hero-detail.component.ts', 'deleted', 'HeroDetailComponent.ts (excerpt)')(format=".")
|
+makeExample('template-syntax/ts/app/hero-detail.component.ts', 'deleted', 'HeroDetailComponent.ts (excerpt)')(format=".")
|
||||||
:marked
|
:marked
|
||||||
When something invokes the `onDeleted()` method, we "emit" a `Hero` object.
|
When something invokes the `onDeleted()` method, we "emit" a `Hero` object.
|
||||||
|
|
||||||
Now imagine a parent component that listens for that event with an Event Binding.
|
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=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-to-component')(format=".")
|
||||||
@ -588,7 +584,7 @@ code-example(format="", language="html").
|
|||||||
|
|
||||||
Evaluation of an Event Binding template expression may have side-effects as this one clearly does.
|
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.
|
They are not just OK (unlike in property bindings); they are expected.
|
||||||
|
|
||||||
The expression could update the model thereby triggering other changes that percolate through the system, changes that
|
The expression could update the model thereby triggering other changes that percolate through the system, changes that
|
||||||
are ultimately displayed in this view and other views.
|
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.
|
The event processing may result in queries and saves to a remote server. It's all good.
|
||||||
@ -609,7 +605,7 @@ code-example(format="", language="html").
|
|||||||
continues or stops with the current element.
|
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 expression returns a falsey value (as does a method with no return value).
|
||||||
Clicking the button in this next example triggers a save;
|
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:
|
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=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-no-propagation')(format=".")
|
||||||
:marked
|
:marked
|
||||||
@ -645,7 +641,7 @@ code-example(format="", language="html").
|
|||||||
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-3')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-3')(format=".")
|
||||||
:marked
|
:marked
|
||||||
That’s an improvement. It should be better.
|
That’s an improvement. It should be better.
|
||||||
|
|
||||||
We shouldn't have to mention the data property twice. Angular should be able to read the component’s data property and set it
|
We shouldn't have to mention the data property twice. Angular should be able to read the component’s data property and set it
|
||||||
with a single declaration — which it can with the `[{ }]` syntax:
|
with a single declaration — which it can with the `[{ }]` syntax:
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-1')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-1')(format=".")
|
||||||
@ -659,11 +655,11 @@ code-example(format="", language="html").
|
|||||||
|
|
||||||
We can write our own two-way binding directive that follows this pattern if we're ever in the mood to do so.
|
We can write our own two-way binding directive that follows this pattern if we're ever in the mood to do so.
|
||||||
:marked
|
:marked
|
||||||
Is `[{ngModel}]` all we need? Is there ever a reason to fall back to its expanded form?
|
Is `[(ngModel)]` all we need? Is there ever a reason to fall back to its expanded form?
|
||||||
|
|
||||||
Well `NgModel` can only set the target property.
|
Well `NgModel` can only set the target property.
|
||||||
What if we need to do something more or something different when the user changes the value?
|
What if we need to do something more or something different when the user changes the value?
|
||||||
|
|
||||||
Let's try something silly like forcing the input value to uppercase.
|
Let's try something silly like forcing the input value to uppercase.
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-4')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'NgModel-4')(format=".")
|
||||||
:marked
|
:marked
|
||||||
@ -677,7 +673,7 @@ figure.image-display
|
|||||||
<a name="directives"></a>
|
<a name="directives"></a>
|
||||||
## Built-in Directives
|
## Built-in Directives
|
||||||
|
|
||||||
Earlier versions of Angular included over seventy built-in directives.
|
Earlier versions of Angular included over seventy built-in directives.
|
||||||
The community contributed many more and individuals have created countless private directives for internal applications.
|
The community contributed many more and individuals have created countless private directives for internal applications.
|
||||||
|
|
||||||
We don’t need many of those directives in Angular 2.
|
We don’t need many of those directives in Angular 2.
|
||||||
@ -727,7 +723,7 @@ figure.image-display
|
|||||||
The `NgStyle` directive may be the better choice
|
The `NgStyle` directive may be the better choice
|
||||||
when we want to set *many* inline styles at the same time.
|
when we want to set *many* inline styles at the same time.
|
||||||
|
|
||||||
We apply `NgStyle` by binding it to a key:value control object.
|
We apply `NgStyle` by binding it to a key:value control object.
|
||||||
Each key of the object is a style name and its value is whatever is appropriate for that style.
|
Each key of the object is a style name and its value is whatever is appropriate for that style.
|
||||||
|
|
||||||
Consider a component method such as `setStyles` that returns an object defining three styles:
|
Consider a component method such as `setStyles` that returns an object defining three styles:
|
||||||
@ -761,25 +757,25 @@ figure.image-display
|
|||||||
:marked
|
:marked
|
||||||
Hiding a sub-tree is quite different from excluding a sub-tree with `NgIf`.
|
Hiding a sub-tree is quite different from excluding a sub-tree with `NgIf`.
|
||||||
|
|
||||||
When we hide the element sub-tree, it remains in the DOM.
|
When we hide the element sub-tree, it remains in the DOM.
|
||||||
Components in the sub-tree are preserved along with their state.
|
Components in the sub-tree are preserved along with their state.
|
||||||
Angular may continue to check for changes even to invisible properties.
|
Angular may continue to check for changes even to invisible properties.
|
||||||
The sub-tree may tie up substantial memory and computing resources.
|
The sub-tree may tie up substantial memory and computing resources.
|
||||||
|
|
||||||
When `NgIf` is `false`, Angular physically removes the element sub-tree from the DOM.
|
When `NgIf` is `false`, Angular physically removes the element sub-tree from the DOM.
|
||||||
It destroys components in the sub-tree along with their state which may free up substantial resources
|
It destroys components in the sub-tree along with their state which may free up substantial resources
|
||||||
resulting in better performance for the user.
|
resulting in better performance for the user.
|
||||||
|
|
||||||
The show/hide technique is probably fine for small element trees.
|
The show/hide technique is probably fine for small element trees.
|
||||||
We should be wary when hiding large trees; `NgIf` may be the safer choice. Always measure before leaping to conclusions.
|
We should be wary when hiding large trees; `NgIf` may be the safer choice. Always measure before leaping to conclusions.
|
||||||
|
|
||||||
<a id="ngSwitch"></a>
|
<a id="ngSwitch"></a>
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
### NgSwitch
|
### NgSwitch
|
||||||
We bind to `NgSwitch` when we want to display *one* element tree (an element and its children)
|
We bind to `NgSwitch` when we want to display *one* element tree (an element and its children)
|
||||||
from a *set* of possible elment trees based on some condition.
|
from a *set* of possible elment trees based on some condition.
|
||||||
Angular only puts the *selected* element tree into the DOM.
|
Angular only puts the *selected* element tree into the DOM.
|
||||||
|
|
||||||
Here’s an example:
|
Here’s an example:
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'NgSwitch')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'NgSwitch')(format=".")
|
||||||
@ -802,10 +798,10 @@ figure.image-display
|
|||||||
:marked
|
:marked
|
||||||
### NgFor
|
### NgFor
|
||||||
`NgFor` is a “repeater” directive. It will be familiar if we’ve written repeaters for other view engines.
|
`NgFor` is a “repeater” directive. It will be familiar if we’ve written repeaters for other view engines.
|
||||||
|
|
||||||
Our goal is to present a list of items. We define a block of HTML that defines how a single item should be displayed.
|
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.
|
We tell Angular to use that block as a template for rendering each item in the list.
|
||||||
|
|
||||||
Here is an example of `NgFor` applied to a simple `<div>`.
|
Here is an example of `NgFor` applied to a simple `<div>`.
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'NgFor-1')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'NgFor-1')(format=".")
|
||||||
:marked
|
:marked
|
||||||
@ -814,7 +810,7 @@ figure.image-display
|
|||||||
|
|
||||||
.alert.is-critical
|
.alert.is-critical
|
||||||
:marked
|
:marked
|
||||||
The leading asterisk (\*) in front of `ngFor` is a critical part of this syntax.
|
The leading asterisk (\*) in front of `ngFor` is a critical part of this syntax.
|
||||||
See the section below on [\* and <template>](#star-template).
|
See the section below on [\* and <template>](#star-template).
|
||||||
:marked
|
:marked
|
||||||
The text assigned to `*ngFor` is the instruction that guides the repeater process.
|
The text assigned to `*ngFor` is the instruction that guides the repeater process.
|
||||||
@ -822,26 +818,26 @@ figure.image-display
|
|||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
#### NgFor Micro-syntax
|
#### NgFor Micro-syntax
|
||||||
The string assigned to `*ngFor` is not a [template expression](#template-expressions).
|
The string assigned to `*ngFor` is not a [template expression](#template-expressions).
|
||||||
It’s a little language of its own called a “micro-syntax” that Angular interprets. In this example it means:
|
It’s a little language of its own called a “micro-syntax” that Angular interprets. In this example it means:
|
||||||
|
|
||||||
>*Take each hero in the `heroes` array, store it in the local `hero` variable, and make it available to the templated HTML
|
>*Take each hero in the `heroes` array, store it in the local `hero` variable, and make it available to the templated HTML
|
||||||
for each iteration*.
|
for each iteration*.
|
||||||
|
|
||||||
Angular translates this instruction into a new set of elements and bindings.
|
Angular translates this instruction into a new set of elements and bindings.
|
||||||
We’ll talk about this in the next section about templates.
|
We’ll talk about this in the next section about templates.
|
||||||
:marked
|
:marked
|
||||||
In our two examples, the `ngFor` directive iterates over the `heroes` array returned by the parent component’s `heroes` property
|
In our two examples, the `ngFor` directive iterates over the `heroes` array returned by the parent component’s `heroes` property
|
||||||
and stamps out instances of the element to which it is applied.
|
and stamps out instances of the element to which it is applied.
|
||||||
Angular creates a fresh instance of the template for each hero in the array.
|
Angular creates a fresh instance of the template for each hero in the array.
|
||||||
|
|
||||||
The (#) character before "hero" identifies a [local template variable](#local-vars) called `hero`.
|
The (#) character before "hero" identifies a [local template variable](#local-vars) called `hero`.
|
||||||
|
|
||||||
We reference this variable within the template to access a hero’s properties as we’re doing in the interpolation
|
We reference this variable within the template to access a hero’s properties as we’re doing in the interpolation
|
||||||
or we can pass it in a binding to a component element as we're doing with `hero-detail`.
|
or we can pass it in a binding to a component element as we're doing with `hero-detail`.
|
||||||
|
|
||||||
#### NgFor with index
|
#### NgFor with index
|
||||||
The `ngFor` directive supports an optional index that increases from 0 to the length of the array for each iteration.
|
The `ngFor` directive supports an optional index that increases from 0 to the length of the array for each iteration.
|
||||||
We can capture that in another local template variable (`i`) and use it in our template too.
|
We can capture that in another local template variable (`i`) and use it in our template too.
|
||||||
|
|
||||||
This next example stamps out rows that display like "1 - Hercules Son of Zeus":
|
This next example stamps out rows that display like "1 - Hercules Son of Zeus":
|
||||||
@ -868,9 +864,9 @@ figure.image-display
|
|||||||
the *template-to-repeat* and the *template-to-include* respectively.
|
the *template-to-repeat* and the *template-to-include* respectively.
|
||||||
|
|
||||||
The (\*) prefix syntax is a convenient way for developers to skip the `<template>` wrapper tags and
|
The (\*) prefix syntax is a convenient way for developers to skip the `<template>` wrapper tags and
|
||||||
focus directly on the HTML element to repeat or include.
|
focus directly on the HTML element to repeat or include.
|
||||||
Angular sees the (*) and expands the HTML into the `<template>` tags for us.
|
Angular sees the (*) and expands the HTML into the `<template>` tags for us.
|
||||||
|
|
||||||
### Expanding `*ngIf`
|
### Expanding `*ngIf`
|
||||||
We can do that ourselves if we wish. Instead of writing ...
|
We can do that ourselves if we wish. Instead of writing ...
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'Template-1')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'Template-1')(format=".")
|
||||||
@ -914,10 +910,10 @@ figure.image-display
|
|||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Local template variables
|
## Local template variables
|
||||||
|
|
||||||
A **local template variable** is a vehicle for moving data across element lines.
|
A **local template variable** is a vehicle for moving data across element lines.
|
||||||
|
|
||||||
We've seen the `#hero` local template variable several times in this chapter,
|
We've seen the `#hero` local template variable several times in this chapter,
|
||||||
most prominently when writing [NgFor](#ngFor) repeaters.
|
most prominently when writing [NgFor](#ngFor) repeaters.
|
||||||
|
|
||||||
In the [* and <templates>](#star-template) segment we learned how Angular expands
|
In the [* and <templates>](#star-template) segment we learned how Angular expands
|
||||||
@ -927,17 +923,17 @@ figure.image-display
|
|||||||
The (#) prefix character in front of "hero" means that we're defining a `hero` variable.
|
The (#) prefix character in front of "hero" means that we're defining a `hero` variable.
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
Some folks don't like the (#) character.
|
Some folks don't like the (#) character.
|
||||||
The `var-` prefix is the “cannonical” alternative to "#". We could have declared our variable as `var-hero`.
|
The `var-` prefix is the “cannonical” alternative to "#". We could have declared our variable as `var-hero`.
|
||||||
:marked
|
:marked
|
||||||
We defined `hero` on the outer `<template>` element where it becomes the current hero item
|
We defined `hero` on the outer `<template>` element where it becomes the current hero item
|
||||||
as Angular iterates through the list of heroes.
|
as Angular iterates through the list of heroes.
|
||||||
|
|
||||||
The `hero` variable appears again in the binding on the inner `<hero-detail>` component element.
|
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.
|
That's how each instance of the `<hero-detail>` gets its hero.
|
||||||
|
|
||||||
### Referencing a local template variable
|
### Referencing a local template variable
|
||||||
|
|
||||||
We can reference a local template variable on the same element, on a sibling element, or on
|
We can reference a local template variable on the same element, on a sibling element, or on
|
||||||
any of its child elements.
|
any of its child elements.
|
||||||
|
|
||||||
@ -956,10 +952,10 @@ figure.image-display
|
|||||||
We defined these variables on the `input` elements.
|
We defined these variables on the `input` elements.
|
||||||
We’re passing those `input` element objects across to the
|
We’re passing those `input` element objects across to the
|
||||||
button elements where they become arguments to the `call()` methods in the event bindings.
|
button elements where they become arguments to the `call()` methods in the event bindings.
|
||||||
|
|
||||||
### NgForm and local template variables
|
### NgForm and local template variables
|
||||||
Let's look at one final example, a Form, the poster child for local template variables.
|
Let's look at one final example, a Form, the poster child for local template variables.
|
||||||
|
|
||||||
The HTML for a form can be quite involved as we saw in the [Forms](forms.html) chapter.
|
The HTML for a form can be quite involved as we saw in the [Forms](forms.html) chapter.
|
||||||
The following is a *simplified* example — and it's not simple at all.
|
The following is a *simplified* example — and it's not simple at all.
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'var-form')
|
+makeExample('template-syntax/ts/app/app.component.html', 'var-form')
|
||||||
@ -969,14 +965,14 @@ figure.image-display
|
|||||||
+makeExample('template-syntax/ts/app/app.component.html', 'var-form-a')
|
+makeExample('template-syntax/ts/app/app.component.html', 'var-form-a')
|
||||||
:marked
|
:marked
|
||||||
What is the value of `theForm`?
|
What is the value of `theForm`?
|
||||||
|
|
||||||
It would be the [HTMLFormElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement)
|
It would be the [HTMLFormElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement)
|
||||||
if Angular hadn't taken it over.
|
if Angular hadn't taken it over.
|
||||||
It's actually `ngForm`, a reference to the Angular built-in `NgForm` directive that wraps the native `HTMLFormElement`
|
It's actually `ngForm`, a reference to the Angular built-in `NgForm` directive that wraps the native `HTMLFormElement`
|
||||||
and endows it with additional super powers such as the ability to
|
and endows it with additional super powers such as the ability to
|
||||||
track the validity of user input.
|
track the validity of user input.
|
||||||
|
|
||||||
This explains how we can disable the submit button by checking `theForm.form.valid`
|
This explains how we can disable the submit button by checking `theForm.form.valid`
|
||||||
and pass an object with rich information to the parent component's `onSubmit` method.
|
and pass an object with rich information to the parent component's `onSubmit` method.
|
||||||
|
|
||||||
<a id="inputs-outputs"></a>
|
<a id="inputs-outputs"></a>
|
||||||
@ -984,25 +980,25 @@ figure.image-display
|
|||||||
:marked
|
:marked
|
||||||
## Input and Output Properties
|
## Input and Output Properties
|
||||||
We can only bind to **target directive** properties that are either **inputs** or **outputs**.
|
We can only bind to **target directive** properties that are either **inputs** or **outputs**.
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
We're drawing a sharp distinction between a data binding **target** and a data binding **source**.
|
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 target is to the *left* of the (=) in a binding expression.
|
||||||
The source is on the *right* of the (=).
|
The source is on the *right* of the (=).
|
||||||
|
|
||||||
Every member of a **source** directive (typically a component) is automatically available for binding.
|
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
|
We don't have to do anything special to access a component member in the quoted template expression
|
||||||
to the right of the (=).
|
to the right of the (=).
|
||||||
|
|
||||||
We have *limited* access to members of a **target** directive (typically a component).
|
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 (=).
|
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*.
|
Also remember that a *component is a directive*.
|
||||||
In this section, we use the terms "directive" and "component" interchangeably.
|
In this section, we use the terms "directive" and "component" interchangeably.
|
||||||
:marked
|
:marked
|
||||||
In this chapter we’ve focused mainly on binding to component members within template expressions
|
In this chapter we’ve focused mainly on binding to component members within template expressions
|
||||||
on the *right side of the binding declaration*.
|
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.
|
A member in that position is a binding “data source”. It's not a target for binding.
|
||||||
|
|
||||||
@ -1040,17 +1036,17 @@ figure.image-display
|
|||||||
Don't do both!
|
Don't do both!
|
||||||
:marked
|
:marked
|
||||||
### Aliasing input/output properties
|
### 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 the property to be different from the internal name.
|
||||||
|
|
||||||
This is frequently the case with [Attribute Directives](attribute-directives.html).
|
This is frequently the case with [Attribute Directives](attribute-directives.html).
|
||||||
Directive consumers expect to bind to the name of the directive.
|
Directive consumers expect to bind to the name of the directive.
|
||||||
For example, we expect to bind to the `myClick` event property of the `MyClickDirective`.
|
For example, we expect to bind to the `myClick` event property of the `MyClickDirective`.
|
||||||
|
|
||||||
The directive name is often a poor choice for the the internal property name
|
The directive name is often a poor choice for the the internal property name
|
||||||
because it rarely describes what the property does.
|
because it rarely describes what the property does.
|
||||||
The corresponding `MyClickDirective` internal property is called `clicks`.
|
The corresponding `MyClickDirective` internal property is called `clicks`.
|
||||||
|
|
||||||
Fortunately, we can alias the internal name to meet the conventional needs of the directive's consumer.
|
Fortunately, we can alias the internal name to meet the conventional needs of the directive's consumer.
|
||||||
We alias in decorator syntax like this:
|
We alias in decorator syntax like this:
|
||||||
+makeExample('template-syntax/ts/app/my-click.directive.ts', 'my-click-output-1')(format=".")
|
+makeExample('template-syntax/ts/app/my-click.directive.ts', 'my-click-output-1')(format=".")
|
||||||
@ -1059,7 +1055,7 @@ figure.image-display
|
|||||||
The equivalent aliasing with the `outputs` array requires a colon-delimited string with
|
The equivalent aliasing with the `outputs` array requires a colon-delimited string with
|
||||||
the internal property name on the left and the public name on the right:
|
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=".")
|
+makeExample('template-syntax/ts/app/my-click.directive.ts', 'my-click-output-2')(format=".")
|
||||||
|
|
||||||
<a id="expression-operators"></a>
|
<a id="expression-operators"></a>
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
@ -1102,7 +1098,7 @@ figure.image-display
|
|||||||
The view still renders but the displayed value is blank; we see only "`The title is`" with nothing after it.
|
The view still renders but the displayed value is blank; we see only "`The title is`" with nothing after it.
|
||||||
That is reasonable behavior. At least the app doesn't crash.
|
That is reasonable behavior. At least the app doesn't crash.
|
||||||
|
|
||||||
Suppose the template expression involves a property path as in this next example
|
Suppose the template expression involves a property path as in this next example
|
||||||
where we’re displaying the `firstName` of a null hero.
|
where we’re displaying the `firstName` of a null hero.
|
||||||
|
|
||||||
code-example(format="" language="html").
|
code-example(format="" language="html").
|
||||||
@ -1121,7 +1117,7 @@ code-example(format="" language="html").
|
|||||||
|
|
||||||
On the other hand, null values in the property path may be OK from time to time,
|
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.
|
especially when we know the data will arrive eventually.
|
||||||
|
|
||||||
While we wait for data, the view should render without complaint and
|
While we wait for data, the view should render without complaint and
|
||||||
the null property path should display as blank just as the `title` property does.
|
the null property path should display as blank just as the `title` property does.
|
||||||
|
|
||||||
@ -1138,7 +1134,7 @@ code-example(format="" language="html").
|
|||||||
Imagine guarding against a null somewhere in a long property path such as `a.b.c.d`.
|
Imagine guarding against a null somewhere in a long property path such as `a.b.c.d`.
|
||||||
|
|
||||||
The Angular **“Elvis” operator ( ?. )** is a more fluent and convenient way to guard against nulls in property paths.
|
The Angular **“Elvis” operator ( ?. )** is a more fluent and convenient way to guard against nulls in property paths.
|
||||||
The expression bails out when it hits the first null value.
|
The expression bails out when it hits the first null value.
|
||||||
The display is blank but the app keeps rolling and there are no errors.
|
The display is blank but the app keeps rolling and there are no errors.
|
||||||
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-6')(format=".")
|
+makeExample('template-syntax/ts/app/app.component.html', 'elvis-6')(format=".")
|
||||||
:marked
|
:marked
|
||||||
|
Loading…
x
Reference in New Issue
Block a user