docs(aio): move cookbooks into guide
Also update all docs with migrated versions from latest angular.io Fixes #14941
This commit is contained in:
parent
6497633529
commit
1847550ad1
|
@ -896,7 +896,7 @@ For more information on pipes, see [Pipes](../guide/pipes.html).
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Displays the collection in the order specified by the expression.
|
Displays the collection in the order specified by the expression.
|
||||||
In this example, the movie title orders the movieList.
|
In this example, the movie title orders the `movieList`.
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Ahead-of-Time Compilation
|
Ahead-of-Time Compilation
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Learn how to use Ahead-of-time compilation
|
Learn how to use Ahead-of-time compilation.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
This cookbook describes how to radically improve performance by compiling _Ahead of Time_ (AOT)
|
This cookbook describes how to radically improve performance by compiling _Ahead of Time_ (AOT)
|
|
@ -2,7 +2,7 @@
|
||||||
Architecture Overview
|
Architecture Overview
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
The basic building blocks of Angular applications
|
The basic building blocks of Angular applications.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
You write Angular applications by composing HTML *templates* with Angularized markup,
|
You write Angular applications by composing HTML *templates* with Angularized markup,
|
||||||
|
|
|
@ -9,7 +9,6 @@ An **Attribute** directive changes the appearance or behavior of a DOM element.
|
||||||
|
|
||||||
# Contents
|
# Contents
|
||||||
|
|
||||||
|
|
||||||
* [Directives overview](#directive-overview)
|
* [Directives overview](#directive-overview)
|
||||||
* [Build a simple attribute directive](#write-directive)
|
* [Build a simple attribute directive](#write-directive)
|
||||||
* [Apply the attribute directive to an element in a template](#apply-directive)
|
* [Apply the attribute directive to an element in a template](#apply-directive)
|
||||||
|
@ -19,9 +18,6 @@ An **Attribute** directive changes the appearance or behavior of a DOM element.
|
||||||
|
|
||||||
Try the <live-example title="Attribute Directive example"></live-example>.
|
Try the <live-example title="Attribute Directive example"></live-example>.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a directive-overview}
|
|
||||||
## Directives overview
|
## Directives overview
|
||||||
|
|
||||||
There are three kinds of directives in Angular:
|
There are three kinds of directives in Angular:
|
||||||
|
@ -38,13 +34,12 @@ Two examples are [NgFor](template-syntax.html#ngFor) and [NgIf](template-syntax.
|
||||||
Learn about them in the [Structural Directives](structural-directives.html) guide.
|
Learn about them in the [Structural Directives](structural-directives.html) guide.
|
||||||
|
|
||||||
*Attribute directives* are used as attributes of elements.
|
*Attribute directives* are used as attributes of elements.
|
||||||
The built-in [NgStyle](template-syntax.html#ngStyle) directive in the [Template Syntax](template-syntax.html) guide, for example,
|
The built-in [NgStyle](template-syntax.html#ngStyle) directive in the
|
||||||
|
[Template Syntax](template-syntax.html) guide, for example,
|
||||||
can change several element styles at the same time.
|
can change several element styles at the same time.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a write-directive}
|
|
||||||
## Build a simple attribute directive
|
## Build a simple attribute directive
|
||||||
|
|
||||||
An attribute directive minimally requires building a controller class annotated with
|
An attribute directive minimally requires building a controller class annotated with
|
||||||
`@Directive`, which specifies the selector that identifies
|
`@Directive`, which specifies the selector that identifies
|
||||||
the attribute.
|
the attribute.
|
||||||
|
@ -53,35 +48,45 @@ The controller class implements the desired directive behavior.
|
||||||
This page demonstrates building a simple _myHighlight_ attribute
|
This page demonstrates building a simple _myHighlight_ attribute
|
||||||
directive to set an element's background color
|
directive to set an element's background color
|
||||||
when the user hovers over that element. You can apply it like this:
|
when the user hovers over that element. You can apply it like this:
|
||||||
|
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/app.component.1.html' region='applied'}
|
|
||||||
|
|
||||||
### Write the directive code
|
### Write the directive code
|
||||||
|
|
||||||
Follow the [setup](setup.html) instructions for creating a new local project
|
Follow the [setup](setup.html) instructions for creating a new local project
|
||||||
named <span ngio-ex>attribute-directives</span>.
|
named <span ngio-ex>attribute-directives</span>.
|
||||||
Create the following source file in `src/app` with the following code:
|
|
||||||
|
Create the following source file in the indicated folder:
|
||||||
|
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/highlight.directive.1.ts'}
|
{@example 'attribute-directives/ts/src/app/highlight.directive.1.ts'}
|
||||||
|
|
||||||
|
The `import` statement specifies symbols from the Angular `core`:
|
||||||
|
|
||||||
|
1. `Directive` provides the functionality of the `@Directive` decorator.
|
||||||
|
1. `ElementRef` [injects](dependency-injection.html) into the directive's constructor
|
||||||
|
so the code can access the DOM element.
|
||||||
|
1. `Input` allows data to flow from the binding expression into the directive.
|
||||||
|
|
||||||
|
Next, the `@Directive` decorator function contains the directive metadata in a configuration object
|
||||||
|
as an argument.
|
||||||
`@Directive` requires a CSS selector to identify
|
`@Directive` requires a CSS selector to identify
|
||||||
the HTML in the template that is associated with the directive.
|
the HTML in the template that is associated with the directive.
|
||||||
The [CSS selector for an attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors)
|
The [CSS selector for an attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors)
|
||||||
is the attribute name in square brackets.
|
is the attribute name in square brackets.
|
||||||
Here, the directive's selector is `[myHighlight]`.
|
Here, the directive's selector is `[myHighlight]`.
|
||||||
Angular locates all elements in the template that have an attribute named `myHighlight`.
|
Angular locates all elements in the template that have an attribute named `myHighlight`.
|
||||||
|
|
||||||
### Why not call it "highlight"?
|
### Why not call it "highlight"?
|
||||||
|
|
||||||
Though *highlight* is a more concise name than *myHighlight* and would work,
|
Though *highlight* is a more concise name than *myHighlight* and would work,
|
||||||
a best practice is to prefix selector names to ensure
|
a best practice is to prefix selector names to ensure
|
||||||
they don't conflict with standard HTML attributes.
|
they don't conflict with standard HTML attributes.
|
||||||
This also reduces the risk of colliding with third-party directive names.
|
This also reduces the risk of colliding with third-party directive names.
|
||||||
|
|
||||||
Make sure you do **not** prefix the `highlight` directive name with **`ng`** because
|
Make sure you do **not** prefix the `highlight` directive name with **`ng`** because
|
||||||
that prefix is reserved for Angular and using it could cause bugs that are difficult to diagnose. For a simple demo, the short prefix, `my`, helps distinguish your custom directive.
|
that prefix is reserved for Angular and using it could cause bugs that are difficult to diagnose.
|
||||||
|
For a simple demo, the short prefix, `my`, helps distinguish your custom directive.
|
||||||
<p>
|
After the `@Directive` metadata comes the directive's controller class,
|
||||||
After the <code> @Directive </code> metadata comes the directive's controller class, called <code> HighlightDirective </code> , which contains the logic for the directive.
|
called `HighlightDirective`, which contains the logic for the directive.
|
||||||
</p>
|
<span if-docs="ts">Exporting `HighlightDirective` makes it accessible to other components.</span>
|
||||||
|
|
||||||
Angular creates a new instance of the directive's controller class for
|
Angular creates a new instance of the directive's controller class for
|
||||||
each matching element, injecting an Angular `ElementRef`
|
each matching element, injecting an Angular `ElementRef`
|
||||||
|
@ -89,29 +94,28 @@ into the constructor.
|
||||||
`ElementRef` is a service that grants direct access to the DOM element
|
`ElementRef` is a service that grants direct access to the DOM element
|
||||||
through its `nativeElement` property.
|
through its `nativeElement` property.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a apply-directive}
|
|
||||||
## Apply the attribute directive
|
## Apply the attribute directive
|
||||||
|
|
||||||
To use the new `HighlightDirective`, create a template that
|
To use the new `HighlightDirective`, create a template that
|
||||||
applies the directive as an attribute to a paragraph (`<p>`) element.
|
applies the directive as an attribute to a paragraph (`<p>`) element.
|
||||||
In Angular terms, the `<p>` element is the attribute **host**.
|
In Angular terms, the `<p>` element is the attribute **host**.
|
||||||
<p>
|
|
||||||
Put the template in its own <code> </code> file that looks like this:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
Put the template in its own <span ngio-ex>app.component.html</span>
|
||||||
|
file that looks like this:
|
||||||
|
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/app.component.1.html'}
|
{@example 'attribute-directives/ts/src/app/app.component.1.html'}
|
||||||
|
|
||||||
Now reference this template in the `AppComponent`:
|
Now reference this template in the `AppComponent`:
|
||||||
|
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/app.component.ts'}
|
{@example 'attribute-directives/ts/src/app/app.component.ts'}
|
||||||
|
|
||||||
Next, add an `import` statement to fetch the `Highlight` directive and
|
Next, add an `import` statement to fetch the `Highlight` directive and
|
||||||
add that class to the `declarations` NgModule metadata. This way Angular
|
add that class to the `declarations` NgModule metadata. This way Angular
|
||||||
recognizes the directive when it encounters `myHighlight` in the template.
|
recognizes the directive when it encounters `myHighlight` in the template.
|
||||||
|
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/app.module.ts'}
|
{@example 'attribute-directives/ts/src/app/app.module.ts'}
|
||||||
|
|
||||||
Now when the app runs, the `myHighlight` directive highlights the paragraph text.
|
Now when the app runs, the `myHighlight` directive highlights the paragraph text.
|
||||||
|
@ -123,8 +127,10 @@ Now when the app runs, the `myHighlight` directive highlights the paragraph text
|
||||||
|
|
||||||
### Your directive isn't working?
|
### Your directive isn't working?
|
||||||
|
|
||||||
Did you remember to add the directive to the `declarations` attribute of `@NgModule`? It is easy to forget!
|
Did you remember to add the directive to the `declarations` attribute of `@NgModule`?
|
||||||
|
It is easy to forget!
|
||||||
Open the console in the browser tools and look for an error like this:
|
Open the console in the browser tools and look for an error like this:
|
||||||
|
|
||||||
<code-example format="nocode">
|
<code-example format="nocode">
|
||||||
EXCEPTION: Template parse errors:
|
EXCEPTION: Template parse errors:
|
||||||
Can't bind to 'myHighlight' since it isn't a known property of 'p'.
|
Can't bind to 'myHighlight' since it isn't a known property of 'p'.
|
||||||
|
@ -140,9 +146,6 @@ It created an instance of the `HighlightDirective` class and
|
||||||
injected a reference to the `<p>` element into the directive's constructor
|
injected a reference to the `<p>` element into the directive's constructor
|
||||||
which sets the `<p>` element's background style to yellow.
|
which sets the `<p>` element's background style to yellow.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a respond-to-user}
|
|
||||||
## Respond to user-initiated events
|
## Respond to user-initiated events
|
||||||
|
|
||||||
Currently, `myHighlight` simply sets an element color.
|
Currently, `myHighlight` simply sets an element color.
|
||||||
|
@ -152,14 +155,10 @@ and respond by setting or clearing the highlight color.
|
||||||
|
|
||||||
Begin by adding `HostListener` to the list of imported symbols;
|
Begin by adding `HostListener` to the list of imported symbols;
|
||||||
add the `Input` symbol as well because you'll need it soon.
|
add the `Input` symbol as well because you'll need it soon.
|
||||||
|
Then add two eventhandlers that respond when the mouse enters or leaves,
|
||||||
{@example 'attribute-directives/ts/src/app/highlight.directive.ts' region='imports'}
|
each adorned by the `HostListener` !{_decorator}.
|
||||||
|
The `@HostListener` !{_decorator} lets you subscribe to events of the DOM
|
||||||
Then add two eventhandlers that respond when the mouse enters or leaves, each adorned by the `HostListener` !{_decorator}.
|
element that hosts an attribute directive, the `<p>` in this case.
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts' region='mouse-methods'}
|
|
||||||
|
|
||||||
The `@HostListener` !{_decorator} lets you subscribe to events of the DOM element that hosts an attribute directive, the `<p>` in this case.
|
|
||||||
|
|
||||||
Of course you could reach into the DOM with standard JavaScript and and attach event listeners manually.
|
Of course you could reach into the DOM with standard JavaScript and and attach event listeners manually.
|
||||||
There are at least three problems with _that_ approach:
|
There are at least three problems with _that_ approach:
|
||||||
|
@ -169,24 +168,19 @@ There are at least three problems with _that_ approach:
|
||||||
1. Talking to DOM API directly isn't a best practice.
|
1. Talking to DOM API directly isn't a best practice.
|
||||||
The handlers delegate to a helper method that sets the color on the DOM element, `#{_priv}el`,
|
The handlers delegate to a helper method that sets the color on the DOM element, `#{_priv}el`,
|
||||||
which you declare and initialize in the constructor.
|
which you declare and initialize in the constructor.
|
||||||
|
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts' region='ctor'}
|
|
||||||
|
|
||||||
Here's the updated directive in full:
|
Here's the updated directive in full:
|
||||||
|
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts'}
|
{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts'}
|
||||||
|
|
||||||
Run the app and confirm that the background color appears when the mouse hovers over the `p` and
|
Run the app and confirm that the background color appears when
|
||||||
disappears as it moves out.
|
the mouse hovers over the `p` and disappears as it moves out.
|
||||||
|
|
||||||
<figure class='image-display'>
|
<figure class='image-display'>
|
||||||
<img src="assets/images/devguide/attribute-directives/highlight-directive-anim.gif" alt="Second Highlight"> </img>
|
<img src="assets/images/devguide/attribute-directives/highlight-directive-anim.gif" alt="Second Highlight"> </img>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a bindings}
|
|
||||||
## Pass values into the directive with an _@Input_ data binding
|
## Pass values into the directive with an _@Input_ data binding
|
||||||
|
|
||||||
Currently the highlight color is hard-coded _within_ the directive. That's inflexible.
|
Currently the highlight color is hard-coded _within_ the directive. That's inflexible.
|
||||||
|
@ -194,9 +188,6 @@ In this section, you give the developer the power to set the highlight color whi
|
||||||
|
|
||||||
Start by adding a `highlightColor` property to the directive class like this:
|
Start by adding a `highlightColor` property to the directive class like this:
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts' region='color'}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a input}
|
{@a input}
|
||||||
### Binding to an _@Input_ property
|
### Binding to an _@Input_ property
|
||||||
|
@ -207,30 +198,15 @@ It's called an *input* property because data flows from the binding expression _
|
||||||
Without that input metadata, Angular rejects the binding; see [below](#why-input "Why add @Input?") for more about that.
|
Without that input metadata, Angular rejects the binding; see [below](#why-input "Why add @Input?") for more about that.
|
||||||
|
|
||||||
Try it by adding the following directive binding variations to the `AppComponent` template:
|
Try it by adding the following directive binding variations to the `AppComponent` template:
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/app.component.1.html' region='color-1'}
|
|
||||||
|
|
||||||
Add a `color` property to the `AppComponent`.
|
Add a `color` property to the `AppComponent`.
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/app.component.1.ts' region='class'}
|
|
||||||
|
|
||||||
Let it control the highlight color with a property binding.
|
Let it control the highlight color with a property binding.
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/app.component.1.html' region='color-2'}
|
|
||||||
|
|
||||||
That's good, but it would be nice to _simultaneously_ apply the directive and set the color _in the same attribute_ like this.
|
That's good, but it would be nice to _simultaneously_ apply the directive and set the color _in the same attribute_ like this.
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/app.component.html' region='color'}
|
|
||||||
|
|
||||||
The `[myHighlight]` attribute binding both applies the highlighting directive to the `<p>` element
|
The `[myHighlight]` attribute binding both applies the highlighting directive to the `<p>` element
|
||||||
and sets the directive's highlight color with a property binding.
|
and sets the directive's highlight color with a property binding.
|
||||||
You're re-using the directive's attribute selector (`[myHighlight]`) to do both jobs.
|
You're re-using the directive's attribute selector (`[myHighlight]`) to do both jobs.
|
||||||
That's a crisp, compact syntax.
|
That's a crisp, compact syntax.
|
||||||
|
|
||||||
You'll have to rename the directive's `highlightColor` property to `myHighlight` because that's now the color property binding name.
|
You'll have to rename the directive's `highlightColor` property to `myHighlight` because that's now the color property binding name.
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts' region='color-2'}
|
|
||||||
|
|
||||||
This is disagreeable. The word, `myHighlight`, is a terrible property name and it doesn't convey the property's intent.
|
This is disagreeable. The word, `myHighlight`, is a terrible property name and it doesn't convey the property's intent.
|
||||||
|
|
||||||
|
|
||||||
|
@ -244,60 +220,54 @@ _Inside_ the directive the property is known as `highlightColor`.
|
||||||
_Outside_ the directive, where you bind to it, it's known as `myHighlight`.
|
_Outside_ the directive, where you bind to it, it's known as `myHighlight`.
|
||||||
|
|
||||||
You get the best of both worlds: the property name you want and the binding syntax you want:
|
You get the best of both worlds: the property name you want and the binding syntax you want:
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/app.component.html' region='color'}
|
|
||||||
|
|
||||||
Now that you're binding to `highlightColor`, modify the `onMouseEnter()` method to use it.
|
Now that you're binding to `highlightColor`, modify the `onMouseEnter()` method to use it.
|
||||||
If someone neglects to bind to `highlightColor`, highlight in "red" by default.
|
If someone neglects to bind to `highlightColor`, highlight in red:
|
||||||
|
Here's the latest version of the directive class.
|
||||||
|
## Write a harness to try it
|
||||||
|
|
||||||
|
It may be difficult to imagine how this directive actually works.
|
||||||
{@example 'attribute-directives/ts/src/app/highlight.directive.3.ts' region='mouse-enter'}
|
|
||||||
|
|
||||||
Here's the latest version of the directive class.## Write a harness to try itIt may be difficult to imagine how this directive actually works.
|
|
||||||
In this section, you'll turn `AppComponent` into a harness that
|
In this section, you'll turn `AppComponent` into a harness that
|
||||||
lets you pick the highlight color with a radio button and bind your color choice to the directive.
|
lets you pick the highlight color with a radio button and bind your color choice to the directive.
|
||||||
|
|
||||||
Update `app.component.html` as follows:
|
Update <span ngio-ex>app.component.html</span> as follows:
|
||||||
Revise the `AppComponent.color` so that it has no initial value.Here is the harness and directive in action.
|
Revise the `AppComponent.color` so that it has no initial value.
|
||||||
|
Here are the harness and directive in action.
|
||||||
|
|
||||||
<figure class='image-display'>
|
<figure class='image-display'>
|
||||||
<img src="assets/images/devguide/attribute-directives/highlight-directive-v2-anim.gif" alt="Highlight v.2"> </img>
|
<img src="assets/images/devguide/attribute-directives/highlight-directive-v2-anim.gif" alt="Highlight v.2"> </img>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a second-property}
|
|
||||||
## Bind to a second property
|
## Bind to a second property
|
||||||
|
|
||||||
This highlight directive has a single customizable property. In a real app, it may need more.
|
This highlight directive has a single customizable property. In a real app, it may need more.
|
||||||
|
|
||||||
At the moment, the default color—the color that prevails until
|
At the moment, the default color—the color that prevails until
|
||||||
the user picks a highlight color—is hard-coded as "red".
|
the user picks a highlight color—is hard-coded as "red".
|
||||||
Let the template developer set the default color.
|
Let the template developer set the default color.
|
||||||
|
|
||||||
Add a second **input** property to `HighlightDirective` called `defaultColor`:Revise the directive's `onMouseEnter` so that it first tries to highlight with the `highlightColor`,
|
Add a second **input** property to `HighlightDirective` called `defaultColor`:
|
||||||
|
Revise the directive's `onMouseEnter` so that it first tries to highlight with the `highlightColor`,
|
||||||
then with the `defaultColor`, and falls back to "red" if both properties are undefined.
|
then with the `defaultColor`, and falls back to "red" if both properties are undefined.
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/highlight.directive.ts' region='mouse-enter'}
|
|
||||||
|
|
||||||
How do you bind to a second property when you're already binding to the `myHighlight` attribute name?
|
How do you bind to a second property when you're already binding to the `myHighlight` attribute name?
|
||||||
|
|
||||||
As with components, you can add as many directive property bindings as you need by stringing them along in the template.
|
As with components, you can add as many directive property bindings as you need by stringing them along in the template.
|
||||||
The developer should be able to write the following template HTML to both bind to the `AppComponent.color`
|
The developer should be able to write the following template HTML to both bind to the `AppComponent.color`
|
||||||
and fall back to "violet" as the default color.
|
and fall back to "violet" as the default color.
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/app.component.html' region='defaultColor'}
|
|
||||||
|
|
||||||
Angular knows that the `defaultColor` binding belongs to the `HighlightDirective`
|
Angular knows that the `defaultColor` binding belongs to the `HighlightDirective`
|
||||||
because you made it _public_ with the `@Input` !{_decorator}.
|
because you made it _public_ with the `@Input` !{_decorator}.
|
||||||
|
|
||||||
Here's how the harness should work when you're done coding.
|
Here's how the harness should work when you're done coding.
|
||||||
|
|
||||||
<figure class='image-display'>
|
<figure class='image-display'>
|
||||||
<img src="assets/images/devguide/attribute-directives/highlight-directive-final-anim.gif" alt="Final Highlight"> </img>
|
<img src="assets/images/devguide/attribute-directives/highlight-directive-final-anim.gif" alt="Final Highlight"> </img>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
This page covered how to:
|
This page covered how to:
|
||||||
|
|
||||||
- [Build an **attribute directive**](#write-directive) that modifies the behavior of an element.
|
- [Build an **attribute directive**](#write-directive) that modifies the behavior of an element.
|
||||||
- [Apply the directive](#apply-directive) to an element in a template.
|
- [Apply the directive](#apply-directive) to an element in a template.
|
||||||
- [Respond to **events**](#respond-to-user) that change the directive's behavior.
|
- [Respond to **events**](#respond-to-user) that change the directive's behavior.
|
||||||
|
@ -341,20 +311,11 @@ The final source code follows:
|
||||||
|
|
||||||
You can also experience and download the <live-example title="Attribute Directive example"></live-example>.
|
You can also experience and download the <live-example title="Attribute Directive example"></live-example>.
|
||||||
|
|
||||||
|
|
||||||
{@a why-input}
|
|
||||||
|
|
||||||
### Appendix: Why add _@Input_?
|
### Appendix: Why add _@Input_?
|
||||||
|
|
||||||
In this demo, the `hightlightColor` property is an ***input*** property of
|
In this demo, the `hightlightColor` property is an ***input*** property of
|
||||||
the `HighlightDirective`. You've seen it applied without an alias:
|
the `HighlightDirective`. You've seen it applied without an alias:
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts' region='color'}
|
|
||||||
|
|
||||||
You've seen it with an alias:
|
You've seen it with an alias:
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/highlight.directive.ts' region='color'}
|
|
||||||
|
|
||||||
Either way, the `@Input` !{_decorator} tells Angular that this property is
|
Either way, the `@Input` !{_decorator} tells Angular that this property is
|
||||||
_public_ and available for binding by a parent component.
|
_public_ and available for binding by a parent component.
|
||||||
Without `@Input`, Angular refuses to bind to the property.
|
Without `@Input`, Angular refuses to bind to the property.
|
||||||
|
@ -377,20 +338,17 @@ Only then can it be bound by some other component or directive.
|
||||||
You can tell if `@Input` is needed by the position of the property name in a binding.
|
You can tell if `@Input` is needed by the position of the property name in a binding.
|
||||||
|
|
||||||
* When it appears in the template expression to the ***right*** of the equals (=),
|
* When it appears in the template expression to the ***right*** of the equals (=),
|
||||||
it belongs to the template's component and does not require the `@Input` !{_decorator}.
|
it belongs to the template's component and does not require the `@Input` !{_decorator}.
|
||||||
|
|
||||||
* When it appears in **square brackets** ([ ]) to the **left** of the equals (=),
|
* When it appears in **square brackets** ([ ]) to the **left** of the equals (=),
|
||||||
the property belongs to some _other_ component or directive;
|
the property belongs to some _other_ component or directive;
|
||||||
that property must be adorned with the `@Input` !{_decorator}.
|
that property must be adorned with the `@Input` !{_decorator}.
|
||||||
|
|
||||||
Now apply that reasoning to the following example:
|
Now apply that reasoning to the following example:
|
||||||
|
|
||||||
{@example 'attribute-directives/ts/src/app/app.component.html' region='color'}
|
|
||||||
|
|
||||||
* The `color` property in the expression on the right belongs to the template's component.
|
* The `color` property in the expression on the right belongs to the template's component.
|
||||||
The template and its component trust each other.
|
The template and its component trust each other.
|
||||||
The `color` property doesn't require the `@Input` !{_decorator}.
|
The `color` property doesn't require the `@Input` !{_decorator}.
|
||||||
|
|
||||||
* The `myHighlight` property on the left refers to an _aliased_ property of the `MyHighlightDirective`,
|
* The `myHighlight` property on the left refers to an _aliased_ property of the `HighlightDirective`,
|
||||||
not a property of the template's component. There are trust issues.
|
not a property of the template's component. There are trust issues.
|
||||||
Therefore, the directive property must carry the `@Input` !{_decorator}.
|
Therefore, the directive property must carry the `@Input` !{_decorator}.
|
|
@ -244,7 +244,7 @@ using <a href="https://saucelabs.com/" target="_blank">SauceLabs</a> and
|
||||||
Angular is built on the latest standards of the web platform.
|
Angular is built on the latest standards of the web platform.
|
||||||
Targeting such a wide range of browsers is challenging because they do not support all features of modern browsers.
|
Targeting such a wide range of browsers is challenging because they do not support all features of modern browsers.
|
||||||
|
|
||||||
You compensate by loading polyfill scripts ("polyfills") on the host web page (`index.html`)
|
You can compensate by loading polyfill scripts ("polyfills") on the host web page (`index.html`)
|
||||||
that implement missing features in JavaScript.
|
that implement missing features in JavaScript.
|
||||||
|
|
||||||
{@example 'quickstart/ts/src/index.html' region='polyfills'}
|
{@example 'quickstart/ts/src/index.html' region='polyfills'}
|
||||||
|
@ -252,12 +252,12 @@ that implement missing features in JavaScript.
|
||||||
A particular browser may require at least one polyfill to run _any_ Angular application.
|
A particular browser may require at least one polyfill to run _any_ Angular application.
|
||||||
You may need additional polyfills for specific features.
|
You may need additional polyfills for specific features.
|
||||||
|
|
||||||
The tables below will help you determine which polyfills to load, depending on the browsers you target and the features you use.
|
The tables below can help you determine which polyfills to load, depending on the browsers you target and the features you use.
|
||||||
|
|
||||||
|
|
||||||
~~~ {.alert.is-important}
|
~~~ {.alert.is-important}
|
||||||
|
|
||||||
The suggested polyfills are the ones we know will run full Angular applications.
|
The suggested polyfills are the ones that run full Angular applications.
|
||||||
You may need additional polyfills to support features not covered by this list.
|
You may need additional polyfills to support features not covered by this list.
|
||||||
Note that polyfills cannot magically transform an old, slow browser into a modern, fast one.
|
Note that polyfills cannot magically transform an old, slow browser into a modern, fast one.
|
||||||
|
|
||||||
|
@ -457,7 +457,7 @@ Below are the polyfills which are used to test the framework itself. They are a
|
||||||
|
|
||||||
|
|
||||||
<th>
|
<th>
|
||||||
Licence
|
License
|
||||||
</th>
|
</th>
|
||||||
|
|
||||||
|
|
||||||
|
@ -517,7 +517,7 @@ Below are the polyfills which are used to test the framework itself. They are a
|
||||||
|
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
MIT / Unicode licence
|
MIT / Unicode license
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
|
||||||
|
@ -611,4 +611,5 @@ Below are the polyfills which are used to test the framework itself. They are a
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
\* Figures are for minified and gzipped code, computed with the <a href="http://closure-compiler.appspot.com/home" target="_blank">closure compiler</a>
|
\* Figures are for minified and gzipped code,
|
||||||
|
computed with the <a href="http://closure-compiler.appspot.com/home" target="_blank">closure compiler</a>.
|
|
@ -2,7 +2,7 @@
|
||||||
Dependency Injection
|
Dependency Injection
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Techniques for Dependency Injection
|
Techniques for Dependency Injection.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
Dependency Injection is a powerful pattern for managing code dependencies.
|
Dependency Injection is a powerful pattern for managing code dependencies.
|
||||||
|
@ -136,7 +136,7 @@ Technically, the `@Injectable()`decorator is only _required_ for a service class
|
||||||
The `LoggerService` doesn't depend on anything. The logger would work if we omitted `@Injectable()`
|
The `LoggerService` doesn't depend on anything. The logger would work if we omitted `@Injectable()`
|
||||||
and the generated code would be slightly smaller.
|
and the generated code would be slightly smaller.
|
||||||
|
|
||||||
But the service would break the moment we gave it a dependency and we'd have to go back and
|
But the service would break the moment we gave it a dependency and we'd have to go back
|
||||||
and add `@Injectable()` to fix it. We add `@Injectable()` from the start for the sake of consistency and to avoid future pain.
|
and add `@Injectable()` to fix it. We add `@Injectable()` from the start for the sake of consistency and to avoid future pain.
|
||||||
|
|
||||||
|
|
||||||
|
@ -362,7 +362,7 @@ Here's a typical example:
|
||||||
|
|
||||||
{@example 'cb-dependency-injection/ts/src/app/hero-bios.component.ts' region='ctor'}
|
{@example 'cb-dependency-injection/ts/src/app/hero-bios.component.ts' region='ctor'}
|
||||||
|
|
||||||
Angular asks the injector for the service associated with the `LoggerService` and
|
Angular asks the injector for the service associated with the `LoggerService`
|
||||||
and assigns the returned value to the `logger` parameter.
|
and assigns the returned value to the `logger` parameter.
|
||||||
|
|
||||||
Where did the injector get that value?
|
Where did the injector get that value?
|
|
@ -2,7 +2,7 @@
|
||||||
Cookbook
|
Cookbook
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
A collection of recipes for common Angular application scenarios
|
A collection of recipes for common Angular application scenarios.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
The *Cookbook* offers answers to common implementation questions.
|
The *Cookbook* offers answers to common implementation questions.
|
|
@ -19,12 +19,12 @@ Discusses `<ng-container>`.
|
||||||
Revised samples are more clear and cover all topics discussed.
|
Revised samples are more clear and cover all topics discussed.
|
||||||
|
|
||||||
## NEW: Samples re-structured with `src/` folder (2017-02-02)
|
## NEW: Samples re-structured with `src/` folder (2017-02-02)
|
||||||
All documentation samples have been realigned with the default folder structure of the angular-cli.
|
All documentation samples have been realigned with the default folder structure of the Angular CLI.
|
||||||
That's a step along the road to basing our sample in the angular-cli.
|
That's a step along the road to basing the sample in the Angular CLI.
|
||||||
But it's also good in its own right.
|
But it's also good in its own right.
|
||||||
It helps clearly separate app code from setup and configuration files.
|
It helps clearly separate app code from setup and configuration files.
|
||||||
|
|
||||||
We've updated all samples with an `src/` folder at the project root.
|
All samples now have a `src/` folder at the project root.
|
||||||
The former `app/` folder moves under `src/`.
|
The former `app/` folder moves under `src/`.
|
||||||
Read about moving your existing project to this structure in
|
Read about moving your existing project to this structure in
|
||||||
<a href="https://github.com/angular/quickstart#updating-to-a-newer-version-of-the-quickstart-repo" target="_blank" target="Migrating samples/quickstart app to the src folder">
|
<a href="https://github.com/angular/quickstart#updating-to-a-newer-version-of-the-quickstart-repo" target="_blank" target="Migrating samples/quickstart app to the src folder">
|
||||||
|
@ -50,24 +50,24 @@ The new [Deployment](deployment.html) guide describes techniques for putting you
|
||||||
It includes important advice on optimizing for production.
|
It includes important advice on optimizing for production.
|
||||||
|
|
||||||
## Hierarchical Dependency Injection: refreshed (2017-01-13)
|
## Hierarchical Dependency Injection: refreshed (2017-01-13)
|
||||||
[Hierarchical Dependency Injection](hierarchical-dependency-injection.html) guide significantly revised.
|
[Hierarchical Dependency Injection](hierarchical-dependency-injection.html) guide is significantly revised.
|
||||||
Closes issue #3086
|
Closes issue #3086.
|
||||||
Revised samples are more clear and cover all topics discussed.
|
Revised samples are clearer and cover all topics discussed.
|
||||||
|
|
||||||
## Miscellaneous (2017-01-05)
|
## Miscellaneous (2017-01-05)
|
||||||
* [Setup](setup.html) guide:
|
* [Setup](setup.html) guide:
|
||||||
added (optional) instructions on how to remove _non-essential_ files.
|
added (optional) instructions on how to remove _non-essential_ files.
|
||||||
* No longer consolidate RxJS operator imports in `rxjs-extensions` file; each file should import what it needs.
|
* No longer consolidate RxJS operator imports in `rxjs-extensions` file; each file should import what it needs.
|
||||||
* All samples prepend template/style URLS URLs w/ `./` ... and so should you.
|
* All samples prepend template/style URLs with `./` as a best practice.
|
||||||
* [Style Guide](style-guide.html): copy edits and revised rules.
|
* [Style Guide](style-guide.html): copy edits and revised rules.
|
||||||
|
|
||||||
## Router: more detail (2016-12-21)
|
## Router: more detail (2016-12-21)
|
||||||
Added more information to the [Router](router.html) guide
|
Added more information to the [Router](router.html) guide
|
||||||
including sections named outlets, wildcard routes, and preload strategies.
|
including sections named outlets, wildcard routes, and preload strategies.
|
||||||
|
|
||||||
## Http: how to set default request headers (and other request options) (2016-12-14)
|
## HTTP: how to set default request headers (and other request options) (2016-12-14)
|
||||||
Added section on how to set default request headers (and other request options) to
|
Added section on how to set default request headers (and other request options) to
|
||||||
[Http](server-communication.html#override-default-request-options) guide.
|
[HTTP](server-communication.html#override-default-request-options) guide.
|
||||||
|
|
||||||
## Testing: added component test plunkers (2016-12-02)
|
## Testing: added component test plunkers (2016-12-02)
|
||||||
Added two plunkers that each test _one simple component_ so you can write a component test plunker of your own: <live-example name="setup" plnkr="quickstart-specs">one</live-example> for the QuickStart seed's `AppComponent` and <live-example name="testing" plnkr="banner-specs">another</live-example> for the Testing guide's `BannerComponent`.
|
Added two plunkers that each test _one simple component_ so you can write a component test plunker of your own: <live-example name="setup" plnkr="quickstart-specs">one</live-example> for the QuickStart seed's `AppComponent` and <live-example name="testing" plnkr="banner-specs">another</live-example> for the Testing guide's `BannerComponent`.
|
||||||
|
@ -79,9 +79,9 @@ translation of alternative texts with `select`.
|
||||||
The sample demonstrates these features too.
|
The sample demonstrates these features too.
|
||||||
|
|
||||||
## Testing: karma file updates (2016-11-30)
|
## Testing: karma file updates (2016-11-30)
|
||||||
* karma.config + karma-test-shim can handle multiple spec source paths;
|
* `karma.config` + `karma-test-shim` can handle multiple spec source paths;
|
||||||
see quickstart issue: [angular/quickstart#294](https://github.com/angular/quickstart/issues/294)
|
see quickstart issue: [angular/quickstart#294](https://github.com/angular/quickstart/issues/294).
|
||||||
* Displays Jasmine Runner output in the karma-launched browser
|
* Displays Jasmine Runner output in the karma-launched browser.
|
||||||
|
|
||||||
## QuickStart Rewrite (2016-11-18)
|
## QuickStart Rewrite (2016-11-18)
|
||||||
The QuickStart is completely rewritten so that it actually is quick.
|
The QuickStart is completely rewritten so that it actually is quick.
|
||||||
|
@ -91,7 +91,7 @@ by downloading (or cloning) the QuickStart github repository.
|
||||||
You are no longer asked to copy-and-paste code into setup files that were not explained anyway.
|
You are no longer asked to copy-and-paste code into setup files that were not explained anyway.
|
||||||
|
|
||||||
## Sync with Angular v.2.2.0 (2016-11-14)
|
## Sync with Angular v.2.2.0 (2016-11-14)
|
||||||
Docs and code samples updated and tested with Angular v.2.2.0
|
Docs and code samples updated and tested with Angular v.2.2.0.
|
||||||
|
|
||||||
## UPDATE: NgUpgrade Guide for the AOT friendly _upgrade/static_ module (2016-11-14)
|
## UPDATE: NgUpgrade Guide for the AOT friendly _upgrade/static_ module (2016-11-14)
|
||||||
The updated [NgUpgrade Guide](upgrade.html) guide covers the
|
The updated [NgUpgrade Guide](upgrade.html) guide covers the
|
||||||
|
@ -101,20 +101,20 @@ facility for migrating from AngularJS to Angular.
|
||||||
The documentation for the version prior to v.2.2.0 has been removed.
|
The documentation for the version prior to v.2.2.0 has been removed.
|
||||||
|
|
||||||
## ES6 described in "TypeScript to JavaScript" (2016-11-14)
|
## ES6 described in "TypeScript to JavaScript" (2016-11-14)
|
||||||
The updated "[TypeScript to JavaScript](../cookbook/ts-to-js.html)" cookbook
|
The updated [TypeScript to JavaScript](../cookbook/ts-to-js.html) cookbook
|
||||||
now explains how to write apps in ES6/7
|
now explains how to write apps in ES6/7
|
||||||
by translating the common idioms in the TypeScript documentation examples
|
by translating the common idioms in the TypeScript documentation examples
|
||||||
(and elsewhere on the web) to ES6/7 and ES5.
|
(and elsewhere on the web) to ES6/7 and ES5.
|
||||||
|
|
||||||
## Sync with Angular v.2.1.1 (2016-10-21)
|
## Sync with Angular v.2.1.1 (2016-10-21)
|
||||||
Docs and code samples updated and tested with Angular v.2.1.0
|
Docs and code samples updated and tested with Angular v.2.1.1.
|
||||||
|
|
||||||
## npm _@types_ packages replace _typings_ (2016-10-20)
|
## npm _@types_ packages replace _typings_ (2016-10-20)
|
||||||
Documentation samples now get TypeScript type information for 3rd party libraries
|
Documentation samples now get TypeScript type information for 3rd party libraries
|
||||||
from npm `@types` packages rather than with the _typings_ tooling.
|
from npm `@types` packages rather than with the _typings_ tooling.
|
||||||
The `typings.json` file is gone.
|
The `typings.json` file is gone.
|
||||||
|
|
||||||
The "[AngularJS Upgrade](upgrade.html)" guide reflects this change.
|
The [AngularJS Upgrade](upgrade.html) guide reflects this change.
|
||||||
The `package.json` installs `@types/angular` and several `@types/angular-...`
|
The `package.json` installs `@types/angular` and several `@types/angular-...`
|
||||||
packages in support of upgrade; these are not needed for pure Angular development.
|
packages in support of upgrade; these are not needed for pure Angular development.
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ _before_ the user navigates to them for improved perceived performance.
|
||||||
New `:enter` and `:leave` aliases make animation more natural.
|
New `:enter` and `:leave` aliases make animation more natural.
|
||||||
|
|
||||||
## Sync with Angular v.2.1.0 (2016-10-12)
|
## Sync with Angular v.2.1.0 (2016-10-12)
|
||||||
Docs and code samples updated and tested with Angular v.2.1.0
|
Docs and code samples updated and tested with Angular v.2.1.0.
|
||||||
|
|
||||||
## NEW "Ahead of time (AOT) Compilation" cookbook (2016-10-11)
|
## NEW "Ahead of time (AOT) Compilation" cookbook (2016-10-11)
|
||||||
The NEW [Ahead of time (AOT) Compilation](../cookbook/aot-compiler.html) cookbook
|
The NEW [Ahead of time (AOT) Compilation](../cookbook/aot-compiler.html) cookbook
|
||||||
|
@ -144,7 +144,7 @@ It demonstrates the basics with a QuickStart app
|
||||||
followed by the more advanced considerations of compiling and bundling the Tour of Heroes.
|
followed by the more advanced considerations of compiling and bundling the Tour of Heroes.
|
||||||
|
|
||||||
## Sync with Angular v.2.0.2 (2016-10-6)
|
## Sync with Angular v.2.0.2 (2016-10-6)
|
||||||
Docs and code samples updated and tested with Angular v.2.0.2
|
Docs and code samples updated and tested with Angular v.2.0.2.
|
||||||
|
|
||||||
## "Routing and Navigation" guide with the _Router Module_ (2016-10-5)
|
## "Routing and Navigation" guide with the _Router Module_ (2016-10-5)
|
||||||
The [Routing and Navigation](router.html) guide now locates route configuration
|
The [Routing and Navigation](router.html) guide now locates route configuration
|
||||||
|
@ -171,16 +171,16 @@ The new "angular-in-memory-web-api" has new features.
|
||||||
|
|
||||||
## "Style Guide" with _NgModules_ (2016-09-27)
|
## "Style Guide" with _NgModules_ (2016-09-27)
|
||||||
|
|
||||||
[StyleGuide](style-guide.html) explains our recommended conventions for Angular modules (NgModule).
|
[StyleGuide](style-guide.html) explains recommended conventions for Angular modules (NgModule).
|
||||||
Barrels now are far less useful and have been removed from the style guide;
|
Barrels now are far less useful and have been removed from the style guide;
|
||||||
they remain valuable but are not a matter of Angular style.
|
they remain valuable but are not a matter of Angular style.
|
||||||
We also relaxed the rule that discouraged use of the `@Component.host` property.
|
Also relaxed the rule that discouraged use of the `@Component.host` property.
|
||||||
|
|
||||||
## _moduleId: module.id_ everywhere (2016-09-25)
|
## _moduleId: module.id_ everywhere (2016-09-25)
|
||||||
|
|
||||||
Sample components that get their templates or styles with `templateUrl` or `styleUrls`
|
Sample components that get their templates or styles with `templateUrl` or `styleUrls`
|
||||||
have been converted to _module-relative_ URLs.
|
have been converted to _module-relative_ URLs.
|
||||||
We added the `moduleId: module.id` property-and-value to their `@Component` metadata.
|
Added the `moduleId: module.id` property-and-value to their `@Component` metadata.
|
||||||
|
|
||||||
This change is a requirement for compilation with AOT compiler when the app loads
|
This change is a requirement for compilation with AOT compiler when the app loads
|
||||||
modules with SystemJS as the samples currently do.
|
modules with SystemJS as the samples currently do.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Component Interaction
|
Component Interaction
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Share information between different directives and components
|
Share information between different directives and components.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
<a id="top"></a>This cookbook contains recipes for common component communication scenarios
|
<a id="top"></a>This cookbook contains recipes for common component communication scenarios
|
||||||
|
@ -118,7 +118,7 @@ the expected `ngOnChanges` calls and values:
|
||||||
|
|
||||||
<a id="child-to-parent"></a>## Parent listens for child event
|
<a id="child-to-parent"></a>## Parent listens for child event
|
||||||
|
|
||||||
The child component exposes an `EventEmitter` property with which it `emits`events when something happens.
|
The child component exposes an `EventEmitter` property with which it `emits` events when something happens.
|
||||||
The parent binds to that event property and reacts to those events.
|
The parent binds to that event property and reacts to those events.
|
||||||
|
|
||||||
The child's `EventEmitter` property is an ***output property***,
|
The child's `EventEmitter` property is an ***output property***,
|
|
@ -100,7 +100,7 @@ For more information, see the [Template Syntax](./template-syntax.html#ngFor) pa
|
||||||
|
|
||||||
Notice the `hero` in the `ngFor` double-quoted instruction;
|
Notice the `hero` in the `ngFor` double-quoted instruction;
|
||||||
it is an example of a template input variable. Read
|
it is an example of a template input variable. Read
|
||||||
more about template input variables in the [microsyntax](./template-syntax.html#ngForMicrosyntax) section of
|
more about template input variables in the [microsyntax](./template-syntax.html#microsyntax) section of
|
||||||
the [Template Syntax](./template-syntax.html) page.
|
the [Template Syntax](./template-syntax.html) page.
|
||||||
|
|
||||||
Angular duplicates the `<li>` for each item in the list, setting the `hero` variable
|
Angular duplicates the `<li>` for each item in the list, setting the `hero` variable
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Dynamic Component Loader
|
Dynamic Component Loader
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Load components dynamically
|
Load components dynamically.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
Component templates are not always fixed. An application may need to load new components at runtime.
|
Component templates are not always fixed. An application may need to load new components at runtime.
|
|
@ -2,7 +2,7 @@
|
||||||
Dynamic Forms
|
Dynamic Forms
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Render dynamic forms with FormGroup
|
Render dynamic forms with FormGroup.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
We can't always justify the cost and time to build handcrafted forms,
|
We can't always justify the cost and time to build handcrafted forms,
|
||||||
|
@ -129,7 +129,7 @@ The `ngSwitch` determines which type of question to display.
|
||||||
In both components we're relying on Angular's **formGroup** to connect the template HTML to the
|
In both components we're relying on Angular's **formGroup** to connect the template HTML to the
|
||||||
underlying control objects, populated from the question model with display and validation rules.
|
underlying control objects, populated from the question model with display and validation rules.
|
||||||
|
|
||||||
`formControlName` and `formGroup` are directives defined in `ReactiveFormsModule`. Our templates can can access these directives directly since we imported `ReactiveFormsModule` from `AppModule`.
|
`formControlName` and `formGroup` are directives defined in `ReactiveFormsModule`. Our templates can access these directives directly since we imported `ReactiveFormsModule` from `AppModule`.
|
||||||
<a id="questionnaire-metadata"></a>## Questionnaire data`DynamicFormComponent` expects the list of questions in the form of an array bound to `@Input() questions`.
|
<a id="questionnaire-metadata"></a>## Questionnaire data`DynamicFormComponent` expects the list of questions in the form of an array bound to `@Input() questions`.
|
||||||
|
|
||||||
The set of questions we have defined for the job application is returned from the `QuestionService`.
|
The set of questions we have defined for the job application is returned from the `QuestionService`.
|
|
@ -2,7 +2,7 @@
|
||||||
Form Validation
|
Form Validation
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Validate user's form entries
|
Validate user's form entries.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ At runtime, Angular interprets the template and derives its _form control model_
|
||||||
|
|
||||||
**Reactive Forms** takes a different approach.
|
**Reactive Forms** takes a different approach.
|
||||||
You create the form control model in code. You write the template with form elements
|
You create the form control model in code. You write the template with form elements
|
||||||
and`form...` directives from the Angular `ReactiveFormsModule`.
|
and `form...` directives from the Angular `ReactiveFormsModule`.
|
||||||
At runtime, Angular binds the template elements to your control model based on your instructions.
|
At runtime, Angular binds the template elements to your control model based on your instructions.
|
||||||
|
|
||||||
This approach requires a bit more effort. *You have to write the control model and manage it*.
|
This approach requires a bit more effort. *You have to write the control model and manage it*.
|
||||||
|
@ -365,7 +365,7 @@ Angular has stock validators that correspond to the standard HTML validation att
|
||||||
The `forbiddenNames` validator on the `"name"` control is a custom validator,
|
The `forbiddenNames` validator on the `"name"` control is a custom validator,
|
||||||
discussed in a separate [section below](#custom-validation).
|
discussed in a separate [section below](#custom-validation).
|
||||||
|
|
||||||
Learn more about `FormBuilder` in a _forthcoming_ chapter on reactive forms.
|
Learn more about `FormBuilder` in the [Introduction to FormBuilder](../guide/reactive-forms.html#formbuilder) section of Reactive Forms guide.
|
||||||
#### Committing hero value changes
|
#### Committing hero value changes
|
||||||
|
|
||||||
In two-way data binding, the user's changes flow automatically from the controls back to the data model properties.
|
In two-way data binding, the user's changes flow automatically from the controls back to the data model properties.
|
|
@ -2,5 +2,5 @@
|
||||||
Glossary
|
Glossary
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Brief definitions of the most important words in the Angular vocabulary
|
Brief definitions of the most important words in the Angular vocabulary.
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ open simultaneously.
|
||||||
<img src="assets/images/devguide/dependency-injection/component-hierarchy.png" alt="injector tree" width="600"> </img>
|
<img src="assets/images/devguide/dependency-injection/component-hierarchy.png" alt="injector tree" width="600"> </img>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
### Injector bubbling
|
### Injector bubbling
|
||||||
|
|
||||||
When a component requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.
|
When a component requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.
|
||||||
If the component's injector lacks the provider, it passes the request up to its parent component's injector.
|
If the component's injector lacks the provider, it passes the request up to its parent component's injector.
|
||||||
|
@ -51,22 +51,24 @@ If it runs out of ancestors, Angular throws an error.
|
||||||
|
|
||||||
You can cap the bubbling. An intermediate component can declare that it is the "host" component.
|
You can cap the bubbling. An intermediate component can declare that it is the "host" component.
|
||||||
The hunt for providers will climb no higher than the injector for that host component.
|
The hunt for providers will climb no higher than the injector for that host component.
|
||||||
This a topic for another day.
|
This is a topic for another day.
|
||||||
### Re-providing a service at different levels
|
### Re-providing a service at different levels
|
||||||
|
|
||||||
You can re-register a provider for a particular dependency token at multiple levels of the injector tree.
|
You can re-register a provider for a particular dependency token at multiple levels of the injector tree.
|
||||||
You don't *have* to re-register providers. You shouldn't do so unless you have a good reason.
|
You don't *have* to re-register providers. You shouldn't do so unless you have a good reason.
|
||||||
But you *can*.
|
But you *can*.
|
||||||
|
|
||||||
As the resolution logic works upwards, the first provider encountered wins.
|
As the resolution logic works upwards, the first provider encountered wins.
|
||||||
Thus, a provider in an intermediate injector intercepts a request for a service from something lower in the tree.
|
Thus, a provider in an intermediate injector intercepts a request for a service from something lower in the tree.
|
||||||
It effectively "reconfigures" and "shadows" a provider at a higher level in the tree.
|
It effectively "reconfigures" and "shadows" a provider at a higher level in the tree.
|
||||||
|
|
||||||
If you only specify providers at the top level (typically the root `AppModule`), the tree of injectors appears to be flat.
|
If you only specify providers at the top level (typically the root `AppModule`), the tree of injectors appears to be flat.
|
||||||
All requests bubble up to the root <span if-docs="ts"><code>NgModule</code></span> injector that you configured with the `!{_bootstrapModule}` method.
|
All requests bubble up to the root <span if-docs="ts"><code>NgModule</code></span> injector that you configured with the `!{_bootstrapModule}` method.
|
||||||
|
|
||||||
## Component injectors
|
## Component injectors
|
||||||
|
|
||||||
The ability to configure one or more providers at different levels opens up interesting and useful possibilities.
|
The ability to configure one or more providers at different levels opens up interesting and useful possibilities.
|
||||||
|
|
||||||
### Scenario: service isolation
|
### Scenario: service isolation
|
||||||
|
|
||||||
Architectural reasons may lead you to restrict access to a service to the application domain where it belongs.
|
Architectural reasons may lead you to restrict access to a service to the application domain where it belongs.
|
||||||
|
@ -74,57 +76,55 @@ Architectural reasons may lead you to restrict access to a service to the applic
|
||||||
The guide sample includes a `VillainsListComponent` that displays a list of villains.
|
The guide sample includes a `VillainsListComponent` that displays a list of villains.
|
||||||
It gets those villains from a `VillainsService`.
|
It gets those villains from a `VillainsService`.
|
||||||
|
|
||||||
While you could provide `VillainsService` in the root `AppModule` (that's where you'll find the `HeroesService`),
|
While you _could_ provide `VillainsService` in the root `AppModule` (that's where you'll find the `HeroesService`),
|
||||||
that would make the `VillainsService` available everywhere in the application, including the _Hero_ workflows.
|
that would make the `VillainsService` available everywhere in the application, including the _Hero_ workflows.
|
||||||
|
|
||||||
If you later modify the `VillainsService`, you could break something in a hero component somewhere.
|
If you later modified the `VillainsService`, you could break something in a hero component somewhere.
|
||||||
That's not supposed to happen but the way you've provided the service creates that risk.
|
That's not supposed to happen but providing the service in the root `AppModule` creates that risk.
|
||||||
|
|
||||||
Instead, provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this:
|
Instead, provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this:
|
||||||
|
By providing `VillainsService` in the `VillainsListComponent` metadata and nowhere else,
|
||||||
|
|
||||||
{@example 'hierarchical-dependency-injection/ts/src/app/villains-list.component.ts' region='metadata'}
|
|
||||||
|
|
||||||
By providing `VillainsService` in the `VillainsListComponent` metadata — and nowhere else —,
|
|
||||||
the service becomes available only in the `VillainsListComponent` and its sub-component tree.
|
the service becomes available only in the `VillainsListComponent` and its sub-component tree.
|
||||||
It's still a singleton, but it's a singleton that exist solely in the _villain_ domain.
|
It's still a singleton, but it's a singleton that exist solely in the _villain_ domain.
|
||||||
|
|
||||||
You are confident that a hero component can't access it. You've reduced your exposure to error.
|
Now you know that a hero component can't access it. You've reduced your exposure to error.
|
||||||
|
|
||||||
### Scenario: multiple edit sessions
|
### Scenario: multiple edit sessions
|
||||||
|
|
||||||
Many applications allow users to work on several open tasks at the same time.
|
Many applications allow users to work on several open tasks at the same time.
|
||||||
For example, in a tax preparation application, the preparer could be working several tax returns,
|
For example, in a tax preparation application, the preparer could be working on several tax returns,
|
||||||
switching from one to the other throughout the day.
|
switching from one to the other throughout the day.
|
||||||
|
|
||||||
This guide demonstrates that scenario with an example in the Tour of Heroes theme.
|
This guide demonstrates that scenario with an example in the Tour of Heroes theme.
|
||||||
Imagine an outer `HeroListComponent` that displays a list of super heroes.
|
Imagine an outer `HeroListComponent` that displays a list of super heroes.
|
||||||
|
|
||||||
To open a hero's tax return, the preparer clicks on a hero name, which opens a component for editing that return.
|
To open a hero's tax return, the preparer clicks on a hero name, which opens a component for editing that return.
|
||||||
Each selected hero tax return opens in its own component and multiple returns can be open at the same time.
|
Each selected hero tax return opens in its own component and multiple returns can be open at the same time.
|
||||||
|
|
||||||
Each tax return component
|
Each tax return component has the following characteristics:
|
||||||
* is its own tax return editing session.
|
* Is its own tax return editing session.
|
||||||
* can change a tax return without affecting a return in another component.
|
* Can change a tax return without affecting a return in another component.
|
||||||
* has the ability to save the changes to its tax return or cancel them.
|
* Has the ability to save the changes to its tax return or cancel them.
|
||||||
|
|
||||||
<figure class='image-display'>
|
<figure class='image-display'>
|
||||||
<img src="assets/images/devguide/dependency-injection/hid-heroes-anim.gif" width="400" alt="Heroes in action"> </img>
|
<img src="assets/images/devguide/dependency-injection/hid-heroes-anim.gif" width="400" alt="Heroes in action"> </img>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
One might suppose that the `TaxReturnComponent` has logic to manage and restore changes.
|
One might suppose that the `HeroTaxReturnComponent` has logic to manage and restore changes.
|
||||||
That would be a pretty easy task for a simple hero tax return.
|
That would be a pretty easy task for a simple hero tax return.
|
||||||
In the real world, with a rich tax return data model, the change management would be tricky.
|
In the real world, with a rich tax return data model, the change management would be tricky.
|
||||||
You might delegate that management to a helper service, as this example does.
|
You might delegate that management to a helper service, as this example does.
|
||||||
|
|
||||||
Here is the `HeroTaxReturnService`.
|
Here is the `HeroTaxReturnService`.
|
||||||
It caches a single `HeroTaxReturn`, tracks changes to that return, and can save or restore it.
|
It caches a single `HeroTaxReturn`, tracks changes to that return, and can save or restore it.
|
||||||
It also delegates to the application-wide, singleton `HeroService`, which it gets by injection.
|
It also delegates to the application-wide singleton `HeroService`, which it gets by injection.
|
||||||
|
|
||||||
|
|
||||||
{@example 'hierarchical-dependency-injection/ts/src/app/hero-tax-return.service.ts'}
|
{@example 'hierarchical-dependency-injection/ts/src/app/hero-tax-return.service.ts'}
|
||||||
|
|
||||||
Here is the `HeroTaxReturnComponent` that makes use of it.
|
Here is the `HeroTaxReturnComponent` that makes use of it.
|
||||||
|
|
||||||
|
|
||||||
{@example 'hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.ts'}
|
{@example 'hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.ts'}
|
||||||
|
|
||||||
The _tax-return-to-edit_ arrives via the input property which is implemented with getters and setters.
|
The _tax-return-to-edit_ arrives via the input property which is implemented with getters and setters.
|
||||||
|
@ -133,29 +133,25 @@ The getter always returns what that service says is the current state of the her
|
||||||
The component also asks the service to save and restore this tax return.
|
The component also asks the service to save and restore this tax return.
|
||||||
|
|
||||||
There'd be big trouble if _this_ service were an application-wide singleton.
|
There'd be big trouble if _this_ service were an application-wide singleton.
|
||||||
Every component would share the same service instance.
|
Every component would share the same service instance.
|
||||||
Each component would overwrite the tax return that belonged to another hero.
|
Each component would overwrite the tax return that belonged to another hero.
|
||||||
What a mess!
|
What a mess!
|
||||||
|
|
||||||
Look closely at the metadata for the `HeroTaxReturnComponent`. Notice the `providers` property.
|
Look closely at the metadata for the `HeroTaxReturnComponent`. Notice the `providers` property.
|
||||||
|
The `HeroTaxReturnComponent` has its own provider of the `HeroTaxReturnService`.
|
||||||
|
Recall that every component _instance_ has its own injector.
|
||||||
{@example 'hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.ts' region='providers'}
|
|
||||||
|
|
||||||
The `HeroTaxReturnComponent` has its own provider of the `HeroTaxReturnService`.
|
|
||||||
Recall that every component _instance_ has its own injector.
|
|
||||||
Providing the service at the component level ensures that _every_ instance of the component gets its own, private instance of the service.
|
Providing the service at the component level ensures that _every_ instance of the component gets its own, private instance of the service.
|
||||||
No tax return overwriting. No mess.
|
No tax return overwriting. No mess.
|
||||||
|
|
||||||
The rest of the scenario code relies on other Angular features and techniques that you can learn about elsewhere in the documentation.
|
The rest of the scenario code relies on other Angular features and techniques that you can learn about elsewhere in the documentation.
|
||||||
You can review it and download it from the <live-example></live-example>
|
You can review it and download it from the <live-example></live-example>.
|
||||||
### Scenario: specialized providers
|
### Scenario: specialized providers
|
||||||
|
|
||||||
Another reason to re-provide a service is to substitute a _more specialized_ implementation of that service,
|
Another reason to re-provide a service is to substitute a _more specialized_ implementation of that service,
|
||||||
deeper in the component tree.
|
deeper in the component tree.
|
||||||
|
|
||||||
Consider again the Car example from the [Dependency Injection](./dependency-injection.html) guide.
|
Consider again the Car example from the [Dependency Injection](./dependency-injection.html) guide.
|
||||||
Suppose you configured the root injector (marked as A) with _generic_ providers for
|
Suppose you configured the root injector (marked as A) with _generic_ providers for
|
||||||
`CarService`, `EngineService` and `TiresService`.
|
`CarService`, `EngineService` and `TiresService`.
|
||||||
|
|
||||||
You create a car component (A) that displays a car constructed from these three generic services.
|
You create a car component (A) that displays a car constructed from these three generic services.
|
||||||
|
@ -181,4 +177,4 @@ its injector produces an instance of `Car` resolved by injector (C) with an `Eng
|
||||||
|
|
||||||
|
|
||||||
The code for this _cars_ scenario is in the `car.components.ts` and `car.services.ts` files of the sample
|
The code for this _cars_ scenario is in the `car.components.ts` and `car.services.ts` files of the sample
|
||||||
which you can review and download from the <live-example></live-example>
|
which you can review and download from the <live-example></live-example>.
|
|
@ -2,7 +2,7 @@
|
||||||
Documentation Overview
|
Documentation Overview
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
How to read and use this documentation
|
How to read and use this documentation.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
This page describes the Angular documentation at a high level.
|
This page describes the Angular documentation at a high level.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Learning Angular
|
Learning Angular
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
A suggested path through the documentation for Angular newcomers
|
A suggested path through the documentation for Angular newcomers.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
Npm Packages
|
Npm Packages
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Recommended npm packages, and how to specify package dependencies
|
Recommended npm packages, and how to specify package dependencies.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
Angular applications and Angular itself depend upon features and functionality provided by a variety of third-party packages.
|
Angular applications and Angular itself depend upon features and functionality provided by a variety of third-party packages.
|
||||||
These packages are maintained and installed with the Node Package Manager (<a href="https://docs.npmjs.com/" target="_blank">npm</a>).
|
These packages are maintained and installed with the Node Package Manager (<a href="https://docs.npmjs.com/" target="_blank">npm</a>).
|
||||||
Node.js and npm are essential to Angular development.
|
Node.js and npm are essential to Angular development.
|
||||||
|
|
||||||
<a href="https://docs.npmjs.com/getting-started/installing-node" target="_blank" title="Installing Node.js and updating npm">
|
<a href="https://docs.npmjs.com/getting-started/installing-node" target="_blank" title="Installing Node.js and updating npm">
|
||||||
Get them now</a> if they're not already installed on your machine.
|
Get them now</a> if they're not already installed on your machine.
|
||||||
|
@ -16,23 +16,28 @@ Get them now</a> if they're not already installed on your machine.
|
||||||
by running the commands `node -v` and `npm -v` in a terminal/console window.
|
by running the commands `node -v` and `npm -v` in a terminal/console window.
|
||||||
Older versions produce errors.
|
Older versions produce errors.
|
||||||
|
|
||||||
We recommend [nvm](https://github.com/creationix/nvm) for managing multiple versions of node and npm. You may need [nvm](https://github.com/creationix/nvm) if you already have projects running on your machine that use other versions of node and npm.
|
Consider using [nvm](https://github.com/creationix/nvm) for managing multiple
|
||||||
We recommend a comprehensive starter-set of packages as specified in the `dependencies` and `devDependencies`
|
versions of node and npm. You may need [nvm](https://github.com/creationix/nvm) if
|
||||||
sections of the <a href="https://docs.npmjs.com/files/package.json" target="_blank">package.json</a> file
|
you already have projects running on your machine that use other versions of node and npm.
|
||||||
installed as described during [Setup](setup.html).You can use other packages but we recommend *this particular set* to start with because (a) they work well together and
|
During [Setup](setup.html), a <a href="https://docs.npmjs.com/files/package.json" target="_blank">package.json</a>
|
||||||
(b) they include everything you'll need to build and run the sample applications in this series.
|
file is installed with a comprehensive starter set of
|
||||||
Note: A cookbook or guide page may require an additional library such as *jQuery*.You'll install more than you need for QuickStart.
|
packages as specified in the `dependencies` and `devDependencies` sections.
|
||||||
No worries!
|
|
||||||
|
You can use other packages but the packages in _this particular set_ work well together and include
|
||||||
|
everything you need to build and run the sample applications in this series.
|
||||||
|
|
||||||
|
Note: A cookbook or guide page may require an additional library such as *jQuery*.You'll install more than you need for the QuickStart guide.
|
||||||
|
No worries!
|
||||||
You only serve to the client those packages that the application actually requests.
|
You only serve to the client those packages that the application actually requests.
|
||||||
|
|
||||||
This page explains what each package does. You can make substitutions later to suit your tastes and experience.
|
This page explains what each package does. You can make substitutions later to suit your tastes and experience.
|
||||||
|
|
||||||
## *dependencies* and *devDependencies*
|
## *dependencies* and *devDependencies*
|
||||||
The `package.json` includes two sets of packages,
|
The `package.json` includes two sets of packages,
|
||||||
[dependencies](#dependencies) and [devDependencies](#dev-dependencies).
|
[dependencies](#dependencies) and [devDependencies](#dev-dependencies).
|
||||||
|
|
||||||
The *dependencies* are essential to *running* the application.
|
The *dependencies* are essential to *running* the application.
|
||||||
The *devDependencies* are only necessary to *develop* the application.
|
The *devDependencies* are only necessary to *develop* the application.
|
||||||
You can exclude them from production installations by adding `--production` to the install command, as follows:
|
You can exclude them from production installations by adding `--production` to the install command, as follows:
|
||||||
<code-example format="." language="bash">
|
<code-example format="." language="bash">
|
||||||
npm install my-application --production
|
npm install my-application --production
|
||||||
|
@ -46,37 +51,40 @@ You can exclude them from production installations by adding `--production` to t
|
||||||
## *dependencies*
|
## *dependencies*
|
||||||
The `dependencies` section of `package.json` contains:
|
The `dependencies` section of `package.json` contains:
|
||||||
|
|
||||||
* ***Features*** - Feature packages give the application framework and utility capabilities.
|
* ***Features***: Feature packages give the application framework and utility capabilities.
|
||||||
|
|
||||||
* ***Polyfills*** - Polyfills plug gaps in the browser's JavaScript implementation.
|
* ***Polyfills***: Polyfills plug gaps in the browser's JavaScript implementation.
|
||||||
|
|
||||||
* ***Other*** - Other libraries that support the application such as `bootstrap` for HTML widgets and styling.
|
* ***Other***: Other libraries that support the application such as `bootstrap` for HTML widgets and styling.
|
||||||
|
|
||||||
### Feature Packages
|
### Feature Packages
|
||||||
|
|
||||||
***@angular/core*** - Critical runtime parts of the framework needed by every application.
|
***@angular/core***: Critical runtime parts of the framework needed by every application.
|
||||||
Includes all metadata decorators, `Component`, `Directive`, dependency injection, and the component lifecycle hooks.
|
Includes all metadata decorators, `Component`, `Directive`, dependency injection, and the component lifecycle hooks.
|
||||||
|
|
||||||
***@angular/common*** - The commonly needed services, pipes, and directives provided by the Angular team.
|
***@angular/common***: The commonly needed services, pipes, and directives provided by the Angular team.
|
||||||
|
|
||||||
***@angular/compiler*** - Angular's *Template Compiler*.
|
***@angular/compiler***: Angular's *Template Compiler*.
|
||||||
It understands templates and can convert them to code that makes the application run and render.
|
It understands templates and can convert them to code that makes the application run and render.
|
||||||
Typically you don’t interact with the compiler directly; rather, you use it indirectly via `platform-browser-dynamic` or the offline template compiler.
|
Typically you don’t interact with the compiler directly; rather, you use it indirectly via `platform-browser-dynamic` or the offline template compiler.
|
||||||
|
|
||||||
***@angular/platform-browser*** - Everything DOM and browser related, especially the pieces that help render into DOM.
|
***@angular/platform-browser***: Everything DOM and browser related, especially
|
||||||
This package also includes the bootstrapStatic method for bootstrapping applications for production builds that pre-compile templates offline.
|
the pieces that help render into the DOM.
|
||||||
|
This package also includes the `bootstrapStatic()` method
|
||||||
|
for bootstrapping applications for production builds that pre-compile templates offline.
|
||||||
|
|
||||||
***@angular/platform-browser-dynamic*** - Includes [Providers](../api/core/index/Provider-type-alias.html) and a [bootstrap](ngmodule.html#bootstrap) method for applications that
|
***@angular/platform-browser-dynamic***: Includes [Providers](../api/core/index/Provider-type-alias.html)
|
||||||
|
and a [bootstrap](ngmodule.html#bootstrap) method for applications that
|
||||||
compile templates on the client. Don’t use offline compilation.
|
compile templates on the client. Don’t use offline compilation.
|
||||||
Use this package for bootstrapping during development and for bootstrapping plunker samples.
|
Use this package for bootstrapping during development and for bootstrapping plunker samples.
|
||||||
|
|
||||||
***@angular/http*** - Angular's http client.
|
***@angular/http***: Angular's HTTP client.
|
||||||
|
|
||||||
***@angular/router*** - Component router.
|
***@angular/router***: Component router.
|
||||||
|
|
||||||
***@angular/upgrade*** - Set of utilities for upgrading AngularJS applications to Angular.
|
***@angular/upgrade***: Set of utilities for upgrading AngularJS applications to Angular.
|
||||||
|
|
||||||
***[system.js](https://github.com/systemjs/systemjs)*** - A dynamic module loader compatible with the
|
***[system.js](https://github.com/systemjs/systemjs)***: A dynamic module loader compatible with the
|
||||||
[ES2015 module](http://www.2ality.com/2014/09/es6-modules-final.html) specification.
|
[ES2015 module](http://www.2ality.com/2014/09/es6-modules-final.html) specification.
|
||||||
Other viable choices include the well-regarded [webpack](https://webpack.github.io/).
|
Other viable choices include the well-regarded [webpack](https://webpack.github.io/).
|
||||||
|
|
||||||
|
@ -94,18 +102,18 @@ Install these polyfills using the npm packages that Angular lists in the *peerDe
|
||||||
|
|
||||||
You must list these packages in the `dependencies` section of your own `package.json`.
|
You must list these packages in the `dependencies` section of your own `package.json`.
|
||||||
|
|
||||||
For background on this requirement, see [Why peerDependencies?](#why-peer-dependencies).***core-js*** - Patches the global context (window) with essential features of ES2015 (ES6).
|
For background on this requirement, see [Why peerDependencies?](#why-peer-dependencies).***core-js***: Patches the global context (window) with essential features of ES2015 (ES6).
|
||||||
You may substitute an alternative polyfill that provides the same core APIs.
|
You may substitute an alternative polyfill that provides the same core APIs.
|
||||||
When these APIs are implemented by the major browsers, this dependency will become unnecessary.
|
When these APIs are implemented by the major browsers, this dependency will become unnecessary.
|
||||||
|
|
||||||
***rxjs*** - A polyfill for the [Observables specification](https://github.com/zenparsing/es-observable) currently before the
|
***rxjs***: A polyfill for the [Observables specification](https://github.com/zenparsing/es-observable) currently before the
|
||||||
[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
|
[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
|
||||||
You can pick a preferred version of *rxjs* (within a compatible version range)
|
You can pick a preferred version of *rxjs* (within a compatible version range)
|
||||||
without waiting for Angular updates.
|
without waiting for Angular updates.
|
||||||
|
|
||||||
***zone.js*** - A polyfill for the [Zone specification](https://gist.github.com/mhevery/63fdcdf7c65886051d55) currently before the
|
***zone.js***: A polyfill for the [Zone specification](https://gist.github.com/mhevery/63fdcdf7c65886051d55) currently before the
|
||||||
[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
|
[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
|
||||||
You can pick a preferred version of *zone.js* to use (within a compatible version range)
|
You can pick a preferred version of *zone.js* to use (within a compatible version range)
|
||||||
without waiting for Angular updates.
|
without waiting for Angular updates.
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,12 +121,12 @@ without waiting for Angular updates.
|
||||||
|
|
||||||
### Other helper libraries
|
### Other helper libraries
|
||||||
|
|
||||||
***angular-in-memory-web-api*** - An Angular-supported library that simulates a remote server's web api
|
***angular-in-memory-web-api***: An Angular-supported library that simulates a remote server's web api
|
||||||
without requiring an actual server or real http calls.
|
without requiring an actual server or real HTTP calls.
|
||||||
Good for demos, samples, and early stage development (before we even have a server).
|
Good for demos, samples, and early stage development (before you even have a server).
|
||||||
Read about it in the [Http Client](server-communication.html#appendix-tour-of-heroes-in-memory-server) page.
|
Read about it in the [HTTP Client](server-communication.html#in-mem-web-api) page.
|
||||||
|
|
||||||
***bootstrap*** - [Bootstrap](http://getbootstrap.com/) is a popular HTML and CSS framework for designing responsive web apps.
|
***bootstrap***: [Bootstrap](http://getbootstrap.com/) is a popular HTML and CSS framework for designing responsive web apps.
|
||||||
Some of the samples improve their appearance with *bootstrap*.
|
Some of the samples improve their appearance with *bootstrap*.
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,39 +136,38 @@ Some of the samples improve their appearance with *bootstrap*.
|
||||||
The packages listed in the *devDependencies* section of the `package.json` help you develop the application.
|
The packages listed in the *devDependencies* section of the `package.json` help you develop the application.
|
||||||
You don't have to deploy them with the production application although there is no harm in doing so.
|
You don't have to deploy them with the production application although there is no harm in doing so.
|
||||||
|
|
||||||
***[concurrently](https://www.npmjs.com/package/concurrently)*** -
|
***[concurrently](https://www.npmjs.com/package/concurrently)***:
|
||||||
A utility to run multiple *npm* commands concurrently on OS/X, Windows, and Linux operating systems.
|
A utility to run multiple *npm* commands concurrently on OS/X, Windows, and Linux operating systems.
|
||||||
|
|
||||||
***[lite-server](https://www.npmjs.com/package/lite-server)*** -
|
***[lite-server](https://www.npmjs.com/package/lite-server)***:
|
||||||
A light-weight, static file server, by [John Papa](http://johnpapa.net/)
|
A light-weight, static file server, by [John Papa](http://johnpapa.net/)
|
||||||
with excellent support for Angular apps that use routing.
|
with excellent support for Angular apps that use routing.
|
||||||
|
|
||||||
***[typescript](https://www.npmjs.com/package/typescript)*** -
|
***[typescript](https://www.npmjs.com/package/typescript)***:
|
||||||
the TypeScript language server, including the *tsc* TypeScript compiler.
|
the TypeScript language server, including the *tsc* TypeScript compiler.
|
||||||
|
|
||||||
***@types/\**** - TypeScript definition files.
|
***@types/\****: TypeScript definition files.
|
||||||
Learn more about it in the [TypeScript Configuration](typescript-configuration.html#typings) chapter.
|
Learn more about it in the [TypeScript Configuration](typescript-configuration.html#typings) guide.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a why-peer-dependencies}
|
{@a why-peer-dependencies}
|
||||||
## Why *peerDependencies*?
|
## Why *peerDependencies*?
|
||||||
|
|
||||||
There isn't a *peerDependencies* section in the QuickStart `package.json`.
|
There isn't a [*peerDependencies*](https://nodejs.org/en/blog/npm/peer-dependencies/) section in the QuickStart `package.json`.
|
||||||
But Angular has a *peerDependencies* section in
|
But Angular has a *peerDependencies* section in
|
||||||
*its* package.json, which has important consequences for your application.
|
*its* `package.json`, which has important consequences for your application.
|
||||||
|
|
||||||
It explains why you load the [polyfill](#polyfills) *dependency* packages in the QuickStart `package.json`,
|
This section explains why you load the [polyfill](#polyfills) *dependency*
|
||||||
|
packages in the QuickStart application's `package.json`,
|
||||||
and why you'll need those packages in your own applications.
|
and why you'll need those packages in your own applications.
|
||||||
|
|
||||||
An explanation of [peer dependencies](https://nodejs.org/en/blog/npm/peer-dependencies/) follows.
|
|
||||||
|
|
||||||
Packages depend on other packages. For example, your application depends on the Angular package.
|
Packages depend on other packages. For example, your application depends on the Angular package.
|
||||||
|
|
||||||
Two packages, "A" and "B", could depend on the same third package "C".
|
Two packages, "A" and "B", could depend on the same third package "C".
|
||||||
"A" and "B" might both list "C" among their *dependencies*.
|
"A" and "B" might both list "C" among their *dependencies*.
|
||||||
|
|
||||||
What if "A" and "B" depend on different versions of "C" ("C1" and "C2"). The npm package system supports that.
|
What if "A" and "B" depend on different versions of "C" ("C1" and "C2"). The npm package system supports that.
|
||||||
It installs "C1" in the `node_modules` folder for "A" and "C2" in the `node_modules` folder for "B".
|
It installs "C1" in the `node_modules` folder for "A" and "C2" in the `node_modules` folder for "B".
|
||||||
Now "A" and "B" have their own copies of "C" and they run without interferring with one another.
|
Now "A" and "B" have their own copies of "C" and they run without interferring with one another.
|
||||||
|
|
||||||
|
@ -174,11 +181,11 @@ The difference between a `dependency` and a `peerDependency` is roughly this:
|
||||||
>A **dependency** says, "I need this thing directly available to *me*."
|
>A **dependency** says, "I need this thing directly available to *me*."
|
||||||
>
|
>
|
||||||
>A **peerDependency** says, "If you want to use me, you need this thing available to *you*."
|
>A **peerDependency** says, "If you want to use me, you need this thing available to *you*."
|
||||||
|
|
||||||
The Angular `package.json` specifies several *peer dependency* packages,
|
The Angular `package.json` specifies several *peer dependency* packages,
|
||||||
each pinned to a particular version of a third-party package.
|
each pinned to a particular version of a third-party package.
|
||||||
|
|
||||||
### We must install Angular's *peerDependencies* ourselves.
|
### You must install Angular's *peerDependencies* yourself.
|
||||||
|
|
||||||
When *npm* installs packages listed in *your* `dependencies` section,
|
When *npm* installs packages listed in *your* `dependencies` section,
|
||||||
it also installs the packages listed within *their* packages `dependencies` sections.
|
it also installs the packages listed within *their* packages `dependencies` sections.
|
||||||
|
@ -191,7 +198,7 @@ the packages listed in Angular's *peerDependencies* section**.
|
||||||
|
|
||||||
Fortunately, *npm* issues a warning (a) When any *peer dependencies* are missing, or (b)
|
Fortunately, *npm* issues a warning (a) When any *peer dependencies* are missing, or (b)
|
||||||
When the application or any of its other dependencies
|
When the application or any of its other dependencies
|
||||||
installs a different version of a *peer dependency*.
|
installs a different version of a *peer dependency*.
|
||||||
|
|
||||||
These warnings guard against accidental failures due to version mismatches.
|
These warnings guard against accidental failures due to version mismatches.
|
||||||
They leave you in control of package and version resolution.
|
They leave you in control of package and version resolution.
|
||||||
|
@ -202,5 +209,5 @@ It is your responsibility to list all *peer dependency* packages **among your ow
|
||||||
|
|
||||||
The Angular polyfill dependencies are hard requirements. Currently, there is no way to make them optional.
|
The Angular polyfill dependencies are hard requirements. Currently, there is no way to make them optional.
|
||||||
|
|
||||||
However, there is an npm feature request for "optional peerDependencies," which would allow you to model this relationship better.
|
However, there is an npm feature request for "optional peerDependencies," which would allow you to model this relationship better.
|
||||||
When this feature request is implemented, Angular will switch from *peerDependencies* to *optionalPeerDependencies* for all polyfills.
|
When this feature request is implemented, Angular will switch from *peerDependencies* to *optionalPeerDependencies* for all polyfills.
|
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,7 @@
|
||||||
Security
|
Security
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Developing for content security in Angular applications
|
Developing for content security in Angular applications.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
This page describes Angular's built-in
|
This page describes Angular's built-in
|
||||||
|
|
|
@ -13,27 +13,50 @@ it isn't covered in this page.Modern browsers support two HTTP-based APIs:
|
||||||
[Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
|
[Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
|
||||||
|
|
||||||
The !{_Angular_http_library} simplifies application programming with the **XHR** and **JSONP** APIs.
|
The !{_Angular_http_library} simplifies application programming with the **XHR** and **JSONP** APIs.
|
||||||
This page covers:
|
# Contents
|
||||||
|
* [Demos](#demos)
|
||||||
- [The Tour of Heroes *HTTP* client demo](#http-client).
|
* [Providing HTTP Services](#http-providers)
|
||||||
- [Fetch data with http.get](#fetch-data).
|
* [The Tour of Heroes *HTTP* client demo](#http-client)
|
||||||
<li if-docs="ts"> [RxJS library](#rxjs).</li>
|
- [The `HeroListComponent` class](#HeroListComponent)
|
||||||
<li if-docs="ts"> [Enable RxJS operators](#enable-rxjs-operators).</li>
|
* [Fetch data with `http.get()`](#fetch-data)
|
||||||
- [Process the response object](#extract-data).
|
<li if-docs="ts"> [RxJS library](#rxjs-library)
|
||||||
- [Always handle errors](#error-handling).
|
<ul>
|
||||||
- [Send data to the server](#update).
|
<li> [Enable RxJS operators](#enable-rxjs-operators)</li>
|
||||||
<li if-docs="ts"> [Fall back to promises](#promises).</li>
|
|
||||||
- [Cross-Origin Requests: Wikipedia example](#cors).
|
|
||||||
<ul if-docs="ts">
|
|
||||||
<li> [Search parameters](#search-parameters).</li>
|
|
||||||
<li> [More fun with observables](#more-observables).</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
- [Guarding against Cross-Site Request Forgery](#xsrf).
|
</li>
|
||||||
- [Override default request headers (and other request options)](#override-default-request-options).
|
* [Process the response object](#extract-data)
|
||||||
- [Appendix: Tour of Heroes _in-memory web api_](#in-mem-web-api).
|
- [Parse to `JSON`](#parse-to-json)
|
||||||
|
- [Do not return the response object](#no-return-response-object)
|
||||||
|
- [Always handle errors](#error-handling)
|
||||||
|
- [`HeroListComponent` error handling](#hero-list-component)
|
||||||
|
* [Send data to the server](#update)
|
||||||
|
- [Headers](#headers)
|
||||||
|
- [JSON results](#json-results)
|
||||||
|
|
||||||
|
<ul><li if-docs="ts"> [Fall back to promises](#promises)</ul>
|
||||||
|
|
||||||
|
* [Cross-Origin Requests: Wikipedia example](#cors)
|
||||||
|
<ul if-docs="ts">
|
||||||
|
<li> [Search Wikipedia](#search-wikipedia)</li>
|
||||||
|
<li> [Search parameters](#search-parameters)</li>
|
||||||
|
<li> [The WikiComponent](#wikicomponent)</li>
|
||||||
|
</ul>
|
||||||
|
* [A wasteful app](#wasteful-app)
|
||||||
|
<li if-docs="ts"> [More fun with Observables](#more-observables)
|
||||||
|
<ul>
|
||||||
|
<li> [Create a stream of search terms](#create-stream)</li>
|
||||||
|
<li> [Listen for search terms](#listen-for-search-terms)</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
* [Guarding against Cross-Site Request Forgery](#xsrf)
|
||||||
|
* [Override default request headers (and other request options)](#override-default-request-options)
|
||||||
|
* [Appendix: Tour of Heroes _in-memory web api_](#in-mem-web-api)
|
||||||
|
|
||||||
A <live-example>live example</live-example> illustrates these topics.
|
A <live-example>live example</live-example> illustrates these topics.
|
||||||
|
|
||||||
|
|
||||||
|
{@a demos}
|
||||||
|
|
||||||
# Demos
|
# Demos
|
||||||
|
|
||||||
This page describes server communication with the help of the following demos:
|
This page describes server communication with the help of the following demos:
|
||||||
|
@ -58,7 +81,7 @@ Register providers by importing other NgModules to the root NgModule in `app.mod
|
||||||
|
|
||||||
|
|
||||||
The `HttpModule` is necessary for making HTTP calls.
|
The `HttpModule` is necessary for making HTTP calls.
|
||||||
Though the JsonpModule isn't necessary for plain HTTP,
|
Though the `JsonpModule` isn't necessary for plain HTTP,
|
||||||
there is a JSONP demo later in this page.
|
there is a JSONP demo later in this page.
|
||||||
Loading its module now saves time.
|
Loading its module now saves time.
|
||||||
## The Tour of Heroes HTTP client demo
|
## The Tour of Heroes HTTP client demo
|
||||||
|
@ -116,7 +139,7 @@ Components are easier to test and debug when their constructors are simple, and
|
||||||
|
|
||||||
{@a HeroService}
|
{@a HeroService}
|
||||||
|
|
||||||
## Fetch data with http.get
|
## Fetch data with _http.get()_
|
||||||
|
|
||||||
In many of the previous samples the app faked the interaction with the server by
|
In many of the previous samples the app faked the interaction with the server by
|
||||||
returning mock heroes in a service like this one:
|
returning mock heroes in a service like this one:
|
||||||
|
@ -149,13 +172,15 @@ Alternatively, you can temporarily target a JSON file by changing the endpoint U
|
||||||
|
|
||||||
{@a extract-data}
|
{@a extract-data}
|
||||||
## Process the response object
|
## Process the response object
|
||||||
Remember that the `getHeroes()` method used an `!{_priv}extractData` helper method to map the `!{_priv}http.get` response object to heroes:
|
Remember that the `getHeroes()` method used an `!{_priv}extractData()` helper method to map the `!{_priv}http.get` response object to heroes:
|
||||||
|
|
||||||
{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='extract-data'}
|
{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='extract-data'}
|
||||||
|
|
||||||
The `response` object doesn't hold the data in a form the app can use directly.
|
The `response` object doesn't hold the data in a form the app can use directly.
|
||||||
You must parse the response data into a JSON object.
|
You must parse the response data into a JSON object.
|
||||||
|
|
||||||
|
|
||||||
|
{@a parse-to-json}
|
||||||
### Parse to JSON
|
### Parse to JSON
|
||||||
Don't expect the decoded JSON to be the heroes !{_array} directly.
|
Don't expect the decoded JSON to be the heroes !{_array} directly.
|
||||||
This server always wraps JSON results in an object with a `data`
|
This server always wraps JSON results in an object with a `data`
|
||||||
|
@ -169,8 +194,12 @@ This is conventional web API behavior, driven by
|
||||||
Make no assumptions about the server API.
|
Make no assumptions about the server API.
|
||||||
Not all servers return an object with a `data` property.
|
Not all servers return an object with a `data` property.
|
||||||
|
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@a no-return-response-object}
|
||||||
### Do not return the response object
|
### Do not return the response object
|
||||||
The `getHeroes()` method _could_ have returned the HTTP response but this wouldn't
|
The `getHeroes()` method _could_ have returned the HTTP response but this wouldn't
|
||||||
be a best practice.
|
be a best practice.
|
||||||
|
@ -225,7 +254,7 @@ just the name of a new hero and returns an `Observable` of `Hero`. It begins lik
|
||||||
|
|
||||||
To implement it, you must know the server's API for creating heroes.
|
To implement it, you must know the server's API for creating heroes.
|
||||||
|
|
||||||
[This sample's data server](#server) follows typical REST guidelines.
|
[This sample's data server](#in-mem-web-api) follows typical REST guidelines.
|
||||||
It expects a [`POST`](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5) request
|
It expects a [`POST`](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5) request
|
||||||
at the same endpoint as `GET` heroes.
|
at the same endpoint as `GET` heroes.
|
||||||
It expects the new hero data to arrive in the body of the request,
|
It expects the new hero data to arrive in the body of the request,
|
||||||
|
@ -240,14 +269,20 @@ The server generates the `id` and returns the entire `JSON` representation
|
||||||
of the new hero including its generated id. The hero arrives tucked inside a response object
|
of the new hero including its generated id. The hero arrives tucked inside a response object
|
||||||
with its own `data` property.
|
with its own `data` property.
|
||||||
|
|
||||||
Now that you know how the API works, implement `addHero()`as follows:
|
Now that you know how the API works, implement `addHero()` as follows:
|
||||||
|
|
||||||
|
|
||||||
{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='addhero'}
|
{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='addhero'}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{@a headers}
|
||||||
### Headers
|
### Headers
|
||||||
|
|
||||||
In the `headers` object, the `Content-Type` specifies that the body represents JSON.
|
In the `headers` object, the `Content-Type` specifies that the body represents JSON.
|
||||||
|
|
||||||
|
|
||||||
|
{@a json-results}
|
||||||
### JSON results
|
### JSON results
|
||||||
|
|
||||||
As with `getHeroes()`, use the `!{_priv}extractData()` helper to [extract the data](#extract-data)
|
As with `getHeroes()`, use the `!{_priv}extractData()` helper to [extract the data](#extract-data)
|
||||||
|
@ -270,10 +305,13 @@ This is called the [same-origin policy](https://en.wikipedia.org/wiki/Same-origi
|
||||||
|
|
||||||
Modern browsers do allow `XHR` requests to servers from a different origin if the server supports the
|
Modern browsers do allow `XHR` requests to servers from a different origin if the server supports the
|
||||||
[CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) protocol.
|
[CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) protocol.
|
||||||
If the server requires user credentials, you'll enable them in the [request headers](#headers).
|
If the server requires user credentials, enable them in the [request headers](#headers).
|
||||||
Some servers do not support CORS but do support an older, read-only alternative called [JSONP](https://en.wikipedia.org/wiki/JSONP).
|
Some servers do not support CORS but do support an older, read-only alternative called [JSONP](https://en.wikipedia.org/wiki/JSONP).
|
||||||
Wikipedia is one such server.
|
Wikipedia is one such server.
|
||||||
This [Stack Overflow answer](http://stackoverflow.com/questions/2067472/what-is-jsonp-all-about/2067584#2067584) covers many details of JSONP.### Search wikipedia
|
This [Stack Overflow answer](http://stackoverflow.com/questions/2067472/what-is-jsonp-all-about/2067584#2067584) covers many details of JSONP.
|
||||||
|
|
||||||
|
{@a search-wikipedia}
|
||||||
|
### Search Wikipedia
|
||||||
|
|
||||||
Here is a simple search that shows suggestions from Wikipedia as the user
|
Here is a simple search that shows suggestions from Wikipedia as the user
|
||||||
types in a text box:
|
types in a text box:
|
||||||
|
@ -289,7 +327,7 @@ types in a text box:
|
||||||
## Guarding against Cross-Site Request Forgery
|
## Guarding against Cross-Site Request Forgery
|
||||||
|
|
||||||
In a cross-site request forgery (CSRF or XSRF), an attacker tricks the user into visiting
|
In a cross-site request forgery (CSRF or XSRF), an attacker tricks the user into visiting
|
||||||
a different web page with malignant code that secretly sends a malicious request to your application's web server,
|
a different web page with malignant code that secretly sends a malicious request to your application's web server.
|
||||||
|
|
||||||
The server and client application must work together to thwart this attack.
|
The server and client application must work together to thwart this attack.
|
||||||
Angular's `Http` client does its part by applying a default `CookieXSRFStrategy` automatically to all requests.
|
Angular's `Http` client does its part by applying a default `CookieXSRFStrategy` automatically to all requests.
|
||||||
|
@ -311,7 +349,7 @@ Request options (such as headers) are merged into the
|
||||||
before the request is processed.
|
before the request is processed.
|
||||||
The `HttpModule` provides these default options via the `RequestOptions` token.
|
The `HttpModule` provides these default options via the `RequestOptions` token.
|
||||||
|
|
||||||
You can override these defaults to suit your application needs.
|
You can override these defaults to suit your application needs
|
||||||
by creating a custom sub-class of `RequestOptions`
|
by creating a custom sub-class of `RequestOptions`
|
||||||
that sets the default options for the application.
|
that sets the default options for the application.
|
||||||
|
|
||||||
|
@ -326,7 +364,7 @@ Then it registers the provider in the root `AppModule`.
|
||||||
{@example 'server-communication/ts/src/app/app.module.ts' region='provide-default-request-options'}
|
{@example 'server-communication/ts/src/app/app.module.ts' region='provide-default-request-options'}
|
||||||
|
|
||||||
|
|
||||||
Remember to include this provider during setup when unit testing the app's HTTP services.After this change, the `header` option setting in `HeroService.addHero` is no longer necessary,
|
Remember to include this provider during setup when unit testing the app's HTTP services.After this change, the `header` option setting in `HeroService.addHero()` is no longer necessary,
|
||||||
|
|
||||||
|
|
||||||
{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='addhero'}
|
{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='addhero'}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Setup for local development
|
Setup for local development
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Install the Angular QuickStart seed for faster, more efficient development on your machine
|
Install the Angular QuickStart seed for faster, more efficient development on your machine.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
|
|
@ -19,15 +19,15 @@ how you can write your own structural directives to do the same thing.
|
||||||
|
|
||||||
- [What are structural directives?](#definition)
|
- [What are structural directives?](#definition)
|
||||||
- [*NgIf* case study](#ngIf)
|
- [*NgIf* case study](#ngIf)
|
||||||
- [Group sibling elements with <ng-container>](#ng-container)
|
- [The asterisk (*) prefix](#asterisk)
|
||||||
- [The asterisk (\*) prefix](#asterisk)
|
- [Inside *NgFor*](#ngFor)
|
||||||
- [Inside *NgFor*](#ngfor)
|
|
||||||
- [microsyntax](#microsyntax)
|
- [microsyntax](#microsyntax)
|
||||||
- [template input variables](#template-input-variable)
|
- [template input variables](#template-input-variable)
|
||||||
- [one structural directive per element](#one-per-element)
|
- [one structural directive per element](#one-per-element)
|
||||||
- [Inside the *NgSwitch* directives](#ngSwitch)
|
- [Inside the *NgSwitch* directives](#ngSwitch)
|
||||||
- [Prefer the (\*) prefix](#prefer-asterisk)
|
- [Prefer the (*) prefix](#prefer-asterisk)
|
||||||
- [The <template> element](#template)
|
- [The <template> element](#template)
|
||||||
|
- [Group sibling elements with <ng-container>](#ng-container)
|
||||||
- [Write a structural directive](#unless)
|
- [Write a structural directive](#unless)
|
||||||
|
|
||||||
Try the <live-example></live-example>.
|
Try the <live-example></live-example>.
|
||||||
|
@ -45,15 +45,13 @@ As with other directives, you apply a structural directive to a _host element_.
|
||||||
The directive then does whatever it's supposed to do with that host element and its descendents.
|
The directive then does whatever it's supposed to do with that host element and its descendents.
|
||||||
|
|
||||||
Structural directives are easy to recognize.
|
Structural directives are easy to recognize.
|
||||||
An asterisk (\*) precedes the directive attribute name as in this example.
|
An asterisk (*) precedes the directive attribute name as in this example.
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='ngif'}
|
|
||||||
|
|
||||||
No brackets. No parentheses. Just `*ngIf` set to a string.
|
No brackets. No parentheses. Just `*ngIf` set to a string.
|
||||||
|
|
||||||
You'll learn in this guide that the [asterisk (\*) is a convenience notation](#asterisk)
|
You'll learn in this guide that the [asterisk (*) is a convenience notation](#asterisk)
|
||||||
and the string is a [_microsyntax_](#microsyntax) rather than the usual [template expression](template-syntax.html#template-expressions).
|
and the string is a [_microsyntax_](#microsyntax) rather than the usual
|
||||||
Angular "de-sugars" this notation into a marked-up `<template>` that surrounds the
|
[template expression](template-syntax.html#template-expressions).
|
||||||
|
Angular desugars this notation into a marked-up `<template>` that surrounds the
|
||||||
host element and its descendents.
|
host element and its descendents.
|
||||||
Each structural directive does something different with that template.
|
Each structural directive does something different with that template.
|
||||||
|
|
||||||
|
@ -61,10 +59,6 @@ Three of the common, built-in structural directives—[NgIf](template-syntax
|
||||||
[NgFor](template-syntax.html#ngFor), and [NgSwitch...](template-syntax.html#ngSwitch)—are
|
[NgFor](template-syntax.html#ngFor), and [NgSwitch...](template-syntax.html#ngSwitch)—are
|
||||||
described in the [_Template Syntax_](template-syntax.html) guide and seen in samples throughout the Angular documentation.
|
described in the [_Template Syntax_](template-syntax.html) guide and seen in samples throughout the Angular documentation.
|
||||||
Here's an example of them in a template:
|
Here's an example of them in a template:
|
||||||
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='built-in'}
|
|
||||||
|
|
||||||
This guide won't repeat how to _use_ them. But it does explain _how they work_
|
This guide won't repeat how to _use_ them. But it does explain _how they work_
|
||||||
and how to [write your own](#unless) structural directive.
|
and how to [write your own](#unless) structural directive.
|
||||||
|
|
||||||
|
@ -91,7 +85,8 @@ you apply the directive to an element in the HTML template.
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
|
||||||
There are two other kinds of Angular directives, described extensively elsewhere: (1) components and (2) attribute directives.
|
There are two other kinds of Angular directives, described extensively elsewhere:
|
||||||
|
(1) components and (2) attribute directives.
|
||||||
|
|
||||||
A *component* manages a region of HTML in the manner of a native HTML element.
|
A *component* manages a region of HTML in the manner of a native HTML element.
|
||||||
Technically it's a directive with a template.
|
Technically it's a directive with a template.
|
||||||
|
@ -107,14 +102,10 @@ You can [only apply one](#one-per-element) _structural_ directive to a host elem
|
||||||
|
|
||||||
{@a ngIf}
|
{@a ngIf}
|
||||||
|
|
||||||
## NgIf Case Study
|
## NgIf case study
|
||||||
|
|
||||||
`NgIf` is the simplest structural directive and the easiest to understand.
|
`NgIf` is the simplest structural directive and the easiest to understand.
|
||||||
It takes a boolean value and makes an entire chunk of the DOM appear or disappear.
|
It takes a boolean expression and makes an entire chunk of the DOM appear or disappear.
|
||||||
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='ngif-true'}
|
|
||||||
|
|
||||||
The `ngIf` directive doesn't hide elements with CSS. It adds and removes them physically from the DOM.
|
The `ngIf` directive doesn't hide elements with CSS. It adds and removes them physically from the DOM.
|
||||||
Confirm that fact using browser developer tools to inspect the DOM.
|
Confirm that fact using browser developer tools to inspect the DOM.
|
||||||
|
|
||||||
|
@ -133,9 +124,6 @@ The component and DOM nodes can be garbage-collected and free up memory.
|
||||||
### Why *remove* rather than *hide*?
|
### Why *remove* rather than *hide*?
|
||||||
|
|
||||||
A directive could hide the unwanted paragraph instead by setting its `display` style to `none`.
|
A directive could hide the unwanted paragraph instead by setting its `display` style to `none`.
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='display-none'}
|
|
||||||
|
|
||||||
While invisible, the element remains in the DOM.
|
While invisible, the element remains in the DOM.
|
||||||
|
|
||||||
<figure class='image-display'>
|
<figure class='image-display'>
|
||||||
|
@ -166,128 +154,24 @@ Before applying a structural directive, you might want to pause for a moment
|
||||||
to consider the consequences of adding and removing elements and of creating and destroying components.
|
to consider the consequences of adding and removing elements and of creating and destroying components.
|
||||||
|
|
||||||
|
|
||||||
{@a ngcontainer}
|
|
||||||
|
|
||||||
|
|
||||||
{@a ng-container}
|
|
||||||
|
|
||||||
## Group sibling elements with <ng-container>
|
|
||||||
|
|
||||||
There's often a _root_ element that can and should host the structural directive.
|
|
||||||
The list element (`<li>`) is a typical host element of an `NgFor` repeater.
|
|
||||||
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='ngfor-li'}
|
|
||||||
|
|
||||||
When there isn't a host element, you can usually wrap the content in a native HTML container element,
|
|
||||||
such as a `<div>`, and attach the directive to that wrapper.
|
|
||||||
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='ngif'}
|
|
||||||
|
|
||||||
Introducing another container element—typically a `<span>` or `<div>`—to
|
|
||||||
group the elements under a single _root_ is usually harmless.
|
|
||||||
_Usually_ ... but not _always_.
|
|
||||||
|
|
||||||
The grouping element may break the template appearance because CSS styles
|
|
||||||
neither expect nor accommodate the new layout.
|
|
||||||
For example, suppose you have the following paragraph layout.
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='ngif-span'}
|
|
||||||
|
|
||||||
You also have a CSS style rule that happens to apply to a `<span>` within a `<p>`aragraph.
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.css' region='p-span'}
|
|
||||||
|
|
||||||
The constructed paragraph renders strangely.
|
|
||||||
<figure class='image-display'>
|
|
||||||
<img src='assets/images/devguide/structural-directives/bad-paragraph.png' alt="spanned paragraph with bad style"> </img>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
The `p span` style, intended for use elsewhere, was inadvertently applied here.
|
|
||||||
|
|
||||||
Another problem: some HTML elements require all immediate children to be of a specific type.
|
|
||||||
For example, the `<select>` tag requires `<option>` children.
|
|
||||||
You can't wrap the _options_ in a conditional `<div>` or a `<span>`.
|
|
||||||
|
|
||||||
When you try this,
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='select-span'}
|
|
||||||
|
|
||||||
the drop down is empty.
|
|
||||||
<figure class='image-display'>
|
|
||||||
<img src='assets/images/devguide/structural-directives/bad-select.png' alt="spanned options don't work"> </img>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
The browser won't display an `<option>` within a `<span>`.
|
|
||||||
|
|
||||||
### <ng-container> to the rescue
|
|
||||||
|
|
||||||
The Angular `<ng-container>` is a grouping element that doesn't interfere with styles or layout
|
|
||||||
because Angular _doesn't put it in the DOM_.
|
|
||||||
|
|
||||||
Here's the conditional paragraph again, this time using `<ng-container>`.
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='ngif-ngcontainer'}
|
|
||||||
|
|
||||||
It renders properly.
|
|
||||||
<figure class='image-display'>
|
|
||||||
<img src='assets/images/devguide/structural-directives/good-paragraph.png' alt="ngcontainer paragraph with proper style"> </img>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
Now conditionally exclude a _select_ `<option>` with `<ng-container>`.
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='select-ngcontainer'}
|
|
||||||
|
|
||||||
The drop down works properly.
|
|
||||||
<figure class='image-display'>
|
|
||||||
<img src='assets/images/devguide/structural-directives/select-ngcontainer-anim.gif' alt="ngcontainer options work properly"> </img>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
The `<ng-container>` is a syntax element recognized by the Angular parser.
|
|
||||||
It's not a directive, component, class, or interface.
|
|
||||||
It's more like the curly braces in a JavaScript `if`-block:
|
|
||||||
|
|
||||||
<code-example language="javascript">
|
|
||||||
if (someCondition) {
|
|
||||||
statement1;
|
|
||||||
statement2;
|
|
||||||
statement3;
|
|
||||||
}
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
Without those braces JavaScript could only execute the first statement
|
|
||||||
when you intend to conditionally execute all of them as a single block.
|
|
||||||
The `<ng-container>` satisfies a similar need in Angular templates.
|
|
||||||
|
|
||||||
|
|
||||||
{@a asterisk}
|
{@a asterisk}
|
||||||
|
|
||||||
## The asterisk (\*) prefix
|
## The asterisk (*) prefix
|
||||||
|
|
||||||
Surely you noticed the asterisk (\*) prefix to the directive name
|
Surely you noticed the asterisk (*) prefix to the directive name
|
||||||
and wondered why it is necessary and what it does.
|
and wondered why it is necessary and what it does.
|
||||||
|
|
||||||
Here is `*ngIf` displaying the hero's name if `hero` exists.
|
Here is `*ngIf` displaying the hero's name if `hero` exists.
|
||||||
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='asterisk'}
|
|
||||||
|
|
||||||
The asterisk is "syntactic sugar" for something a bit more complicated.
|
The asterisk is "syntactic sugar" for something a bit more complicated.
|
||||||
Internally, Angular "de-sugars" it in two stages.
|
Internally, Angular desugars it in two stages.
|
||||||
First, it translates the `*ngIf="..."` into a template _attribute_, `template="ngIf ..."`, like this.
|
First, it translates the `*ngIf="..."` into a template _attribute_, `template="ngIf ..."`, like this.
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='ngif-template-attr'}
|
|
||||||
|
|
||||||
Then it translates the template _attribute_ into a template _element_, wrapped around the host element, like this.
|
Then it translates the template _attribute_ into a template _element_, wrapped around the host element, like this.
|
||||||
|
* The `*ngIf` directive moved to the `<template>` element where it became a property binding,`[ngIf]`.
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='ngif-template'}
|
* The rest of the `<div>`, including its class attribute, moved inside the `<template>` element.
|
||||||
|
|
||||||
* The `*ngIf` directive moved to the `<template>` tag where it became a property binding,`[ngIf]`.
|
|
||||||
* The rest of the `<div>`, including its class attribute, moved inside the `<template>` tag.
|
|
||||||
|
|
||||||
None of these forms are actually rendered.
|
None of these forms are actually rendered.
|
||||||
Only the finished product ends up in the DOM.
|
Only the finished product ends up in the DOM.
|
||||||
|
|
||||||
<figure class='image-display'>
|
<figure class='image-display'>
|
||||||
<img src='assets/images/devguide/structural-directives/hero-div-in-dom.png' alt="hero div in DOM"> </img>
|
<img src='assets/images/devguide/structural-directives/hero-div-in-dom.png' alt="hero div in DOM"> </img>
|
||||||
</figure>
|
</figure>
|
||||||
|
@ -295,25 +179,22 @@ Only the finished product ends up in the DOM.
|
||||||
Angular consumed the `<template>` content during its actual rendering and
|
Angular consumed the `<template>` content during its actual rendering and
|
||||||
replaced the `<template>` with a diagnostic comment.
|
replaced the `<template>` with a diagnostic comment.
|
||||||
|
|
||||||
The [`NgFor`](#ngfor) and [`NgSwitch...`](#ngswitch) directives follow the same pattern.
|
The [`NgFor`](#ngFor) and [`NgSwitch...`](#ngSwitch) directives follow the same pattern.
|
||||||
|
|
||||||
|
|
||||||
{@a ngfor}
|
{@a ngFor}
|
||||||
|
|
||||||
## Inside _*ngFor_
|
## Inside _*ngFor_
|
||||||
|
|
||||||
Angular transforms the `*ngFor` in similar fashion from asterisk (\*) syntax through
|
Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax through
|
||||||
template _attribute_ to template _element_.
|
template _attribute_ to template _element_.
|
||||||
|
|
||||||
Here's a full-featured application of `NgFor`, written all three ways:
|
Here's a full-featured application of `NgFor`, written all three ways:
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='inside-ngfor'}
|
|
||||||
|
|
||||||
This is manifestly more complicated than `ngIf` and rightly so.
|
This is manifestly more complicated than `ngIf` and rightly so.
|
||||||
The `NgFor` directive has more features, both required and optional, than the `NgIf` shown in this guide.
|
The `NgFor` directive has more features, both required and optional, than the `NgIf` shown in this guide.
|
||||||
At minimum `NgFor` needs a looping variable (`let hero`) and a list (`heroes`).
|
At minimum `NgFor` needs a looping variable (`let hero`) and a list (`heroes`).
|
||||||
|
|
||||||
You enable these features in the string assigned to `ngFor`, which you write in Angular's [microsyntax](microsyntax).
|
You enable these features in the string assigned to `ngFor`, which you write in Angular's [microsyntax](#microsyntax).
|
||||||
|
|
||||||
|
|
||||||
~~~ {.alert.is-helpful}
|
~~~ {.alert.is-helpful}
|
||||||
|
@ -328,7 +209,8 @@ In this example, the `[ngClass]="odd"` stays on the `<div>`.
|
||||||
|
|
||||||
|
|
||||||
{@a microsyntax}
|
{@a microsyntax}
|
||||||
### microsyntax
|
### Microsyntax
|
||||||
|
|
||||||
The Angular microsyntax lets you configure a directive in a compact, friendly string.
|
The Angular microsyntax lets you configure a directive in a compact, friendly string.
|
||||||
The microsyntax parser translates that string into attributes on the `<template>`:
|
The microsyntax parser translates that string into attributes on the `<template>`:
|
||||||
|
|
||||||
|
@ -368,18 +250,18 @@ Studying the source code for `NgIf` and `NgFor` is a great way to learn more.
|
||||||
### Template input variable
|
### Template input variable
|
||||||
|
|
||||||
A _template input variable_ is a variable whose value you can reference _within_ a single instance of the template.
|
A _template input variable_ is a variable whose value you can reference _within_ a single instance of the template.
|
||||||
There are several such variables in this example: `hero`, `li`, and `odd`.
|
There are several such variables in this example: `hero`, `i`, and `odd`.
|
||||||
All are preceded by the keyword `let`.
|
All are preceded by the keyword `let`.
|
||||||
|
|
||||||
A _template input variable_ is **_not_** the same as a
|
A _template input variable_ is **_not_** the same as a
|
||||||
[template _reference_ variable](template-syntax.html#ref-vars),
|
[template _reference_ variable](template-syntax.html#ref-vars),
|
||||||
neither _semantically_ nor _syntactically_.
|
neither _semantically_ nor _syntactically_.
|
||||||
|
|
||||||
You declare a template _input_ variable declaration with the `let` keyword (`let hero`).
|
You declare a template _input_ variable using the `let` keyword (`let hero`).
|
||||||
The variable's scope is limited to a _single instance_ of the repeated template.
|
The variable's scope is limited to a _single instance_ of the repeated template.
|
||||||
You can use the same variable name again in the definition of other structural directives.
|
You can use the same variable name again in the definition of other structural directives.
|
||||||
|
|
||||||
You declare a template _reference_ variable declaration by prefixing the variable name with `#` (`#var`).
|
You declare a template _reference_ variable by prefixing the variable name with `#` (`#var`).
|
||||||
A _reference_ variable refers to its attached element, component or directive.
|
A _reference_ variable refers to its attached element, component or directive.
|
||||||
It can be accessed _anywhere_ in the _entire template_.
|
It can be accessed _anywhere_ in the _entire template_.
|
||||||
|
|
||||||
|
@ -404,16 +286,13 @@ There's an easy solution for this use case: put the `*ngIf` on a container eleme
|
||||||
One or both elements can be an [`ng-container`](#ngcontainer) so you don't have to introduce extra levels of HTML.
|
One or both elements can be an [`ng-container`](#ngcontainer) so you don't have to introduce extra levels of HTML.
|
||||||
|
|
||||||
|
|
||||||
{@a ngswitch}
|
{@a ngSwitch}
|
||||||
|
|
||||||
## Inside the _NgSwitch_ directives
|
## Inside _NgSwitch_ directives
|
||||||
|
|
||||||
The Angular _NgSwitch_ is actually a set of cooperating directives: `NgSwitch`, `NgSwitchCase`, and `NgSwitchDefault`.
|
The Angular _NgSwitch_ is actually a set of cooperating directives: `NgSwitch`, `NgSwitchCase`, and `NgSwitchDefault`.
|
||||||
|
|
||||||
Here's an example.
|
Here's an example.
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='ngswitch'}
|
|
||||||
|
|
||||||
The switch value assigned to `NgSwitch` (`hero.emotion`) determines which
|
The switch value assigned to `NgSwitch` (`hero.emotion`) determines which
|
||||||
(if any) of the switch cases are displayed.
|
(if any) of the switch cases are displayed.
|
||||||
|
|
||||||
|
@ -422,7 +301,7 @@ It's an _attribute_ directive that controls the behavior of the other two switch
|
||||||
That's why you write `[ngSwitch]`, never `*ngSwitch`.
|
That's why you write `[ngSwitch]`, never `*ngSwitch`.
|
||||||
|
|
||||||
`NgSwitchCase` and `NgSwitchDefault` _are_ structural directives.
|
`NgSwitchCase` and `NgSwitchDefault` _are_ structural directives.
|
||||||
You attach them to elements using the asterisk (\*) prefix notation.
|
You attach them to elements using the asterisk (*) prefix notation.
|
||||||
An `NgSwitchCase` displays its host element when its value matches the switch value.
|
An `NgSwitchCase` displays its host element when its value matches the switch value.
|
||||||
The `NgSwitchDefault` displays its host element when no sibling `NgSwitchCase` matches the switch value.
|
The `NgSwitchDefault` displays its host element when no sibling `NgSwitchCase` matches the switch value.
|
||||||
|
|
||||||
|
@ -430,20 +309,14 @@ The element to which you apply a directive is its _host_ element.
|
||||||
The `<happy-hero>` is the host element for the happy `*ngSwitchCase`.
|
The `<happy-hero>` is the host element for the happy `*ngSwitchCase`.
|
||||||
The `<unknown-hero>` is the host element for the `*ngSwitchDefault`.
|
The `<unknown-hero>` is the host element for the `*ngSwitchDefault`.
|
||||||
As with other structural directives, the `NgSwitchCase` and `NgSwitchDefault`
|
As with other structural directives, the `NgSwitchCase` and `NgSwitchDefault`
|
||||||
can be "de-sugared" into the template _attribute_ form.
|
can be desugared into the template _attribute_ form.
|
||||||
|
That, in turn, can be desugared into the `<template>` element form.
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='ngswitch-template-attr'}
|
|
||||||
|
|
||||||
That, in turn, can be "de-sugared" into the `<template>` element form.
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='ngswitch-template'}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a prefer-asterisk}
|
{@a prefer-asterisk}
|
||||||
## Prefer the asterisk (\*) syntax.
|
## Prefer the asterisk (*) syntax.
|
||||||
|
|
||||||
The asterisk (\*) syntax is more clear than the other "de-sugared" forms.
|
The asterisk (*) syntax is more clear than the other desugared forms.
|
||||||
Use [<ng-container>](#ng-container) when there's no single element
|
Use [<ng-container>](#ng-container) when there's no single element
|
||||||
to host the directive.
|
to host the directive.
|
||||||
|
|
||||||
|
@ -461,37 +334,116 @@ is a formula for rendering HTML.
|
||||||
It is never displayed directly.
|
It is never displayed directly.
|
||||||
In fact, before rendering the view, Angular _replaces_ the `<template>` and its contents with a comment.
|
In fact, before rendering the view, Angular _replaces_ the `<template>` and its contents with a comment.
|
||||||
|
|
||||||
If there is no structural directive, if you merely wrap some elements in a `<template>` and do nothing with it,
|
If there is no structural directive and you merely wrap some elements in a `<template>`,
|
||||||
those elements disappear.
|
those elements disappear.
|
||||||
That's the fate of the middle "hip" in the phrase "Hip! Hip! Hooray!".
|
That's the fate of the middle "Hip!" in the phrase "Hip! Hip! Hooray!".
|
||||||
|
Angular erases the middle "Hip!", leaving the cheer a bit less enthusiastic.
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='template-tag'}
|
|
||||||
|
|
||||||
Angular erases the middle "hip", leaving the cheer a bit less enthusiastic.
|
|
||||||
<figure class='image-display'>
|
<figure class='image-display'>
|
||||||
<img src='assets/images/devguide/structural-directives/template-rendering.png' width="350" alt="template tag rendering"> </img>
|
<img src='assets/images/devguide/structural-directives/template-rendering.png' width="350" alt="template tag rendering"> </img>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
A structural directive puts a `<template>` to work
|
A structural directive puts a `<template>` to work
|
||||||
as you'll see when you write your own structural directive.
|
as you'll see when you [write your own structural directive](#unless).
|
||||||
|
|
||||||
|
|
||||||
|
{@a ngcontainer}
|
||||||
|
|
||||||
|
|
||||||
|
{@a ng-container}
|
||||||
|
|
||||||
|
## Group sibling elements with <ng-container>
|
||||||
|
|
||||||
|
There's often a _root_ element that can and should host the structural directive.
|
||||||
|
The list element (`<li>`) is a typical host element of an `NgFor` repeater.
|
||||||
|
When there isn't a host element, you can usually wrap the content in a native HTML container element,
|
||||||
|
such as a `<div>`, and attach the directive to that wrapper.
|
||||||
|
Introducing another container element—typically a `<span>` or `<div>`—to
|
||||||
|
group the elements under a single _root_ is usually harmless.
|
||||||
|
_Usually_ ... but not _always_.
|
||||||
|
|
||||||
|
The grouping element may break the template appearance because CSS styles
|
||||||
|
neither expect nor accommodate the new layout.
|
||||||
|
For example, suppose you have the following paragraph layout.
|
||||||
|
You also have a CSS style rule that happens to apply to a `<span>` within a `<p>`aragraph.
|
||||||
|
The constructed paragraph renders strangely.
|
||||||
|
|
||||||
|
<figure class='image-display'>
|
||||||
|
<img src='assets/images/devguide/structural-directives/bad-paragraph.png' alt="spanned paragraph with bad style"> </img>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
The `p span` style, intended for use elsewhere, was inadvertently applied here.
|
||||||
|
|
||||||
|
Another problem: some HTML elements require all immediate children to be of a specific type.
|
||||||
|
For example, the `<select>` element requires `<option>` children.
|
||||||
|
You can't wrap the _options_ in a conditional `<div>` or a `<span>`.
|
||||||
|
|
||||||
|
When you try this,
|
||||||
|
the drop down is empty.
|
||||||
|
|
||||||
|
<figure class='image-display'>
|
||||||
|
<img src='assets/images/devguide/structural-directives/bad-select.png' alt="spanned options don't work"> </img>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
The browser won't display an `<option>` within a `<span>`.
|
||||||
|
|
||||||
|
### <ng-container> to the rescue
|
||||||
|
|
||||||
|
The Angular `<ng-container>` is a grouping element that doesn't interfere with styles or layout
|
||||||
|
because Angular _doesn't put it in the DOM_.
|
||||||
|
|
||||||
|
Here's the conditional paragraph again, this time using `<ng-container>`.
|
||||||
|
It renders properly.
|
||||||
|
|
||||||
|
<figure class='image-display'>
|
||||||
|
<img src='assets/images/devguide/structural-directives/good-paragraph.png' alt="ngcontainer paragraph with proper style"> </img>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
Now conditionally exclude a _select_ `<option>` with `<ng-container>`.
|
||||||
|
The drop down works properly.
|
||||||
|
|
||||||
|
<figure class='image-display'>
|
||||||
|
<img src='assets/images/devguide/structural-directives/select-ngcontainer-anim.gif' alt="ngcontainer options work properly"> </img>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
The `<ng-container>` is a syntax element recognized by the Angular parser.
|
||||||
|
It's not a directive, component, class, or interface.
|
||||||
|
It's more like the curly braces in a JavaScript `if`-block:
|
||||||
|
|
||||||
|
<code-example language="javascript">
|
||||||
|
if (someCondition) {
|
||||||
|
statement1;
|
||||||
|
statement2;
|
||||||
|
statement3;
|
||||||
|
}
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
Without those braces, JavaScript would only execute the first statement
|
||||||
|
when you intend to conditionally execute all of them as a single block.
|
||||||
|
The `<ng-container>` satisfies a similar need in Angular templates.
|
||||||
|
|
||||||
|
|
||||||
{@a unless}
|
{@a unless}
|
||||||
|
|
||||||
## Write a structural directive
|
## Write a structural directive
|
||||||
In this section, you write a `UnlessDirective` structural directive
|
|
||||||
|
In this section, you write an `UnlessDirective` structural directive
|
||||||
that does the opposite of `NgIf`.
|
that does the opposite of `NgIf`.
|
||||||
`NgIf` displays the template content when the condition is `true`.
|
`NgIf` displays the template content when the condition is `true`.
|
||||||
`UnlessDirective` displays the content when the condition is ***false***.
|
`UnlessDirective` displays the content when the condition is ***false***.
|
||||||
|
Creating a directive is similar to creating a component.
|
||||||
|
|
||||||
|
* Import the `Directive` decorator (instead of the `Component` decorator).
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='myUnless-1'}
|
* Import the `Input`, `TemplateRef`, and `ViewContainerRef` symbols; you'll need them for _any_ structural directive.
|
||||||
|
|
||||||
|
* Apply the decorator to the directive class.
|
||||||
|
|
||||||
|
* Set the CSS *attribute selector* that identifies the directive when applied to an element in a template.
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/unless.directive.ts' region='skeleton'}
|
Here's how you might begin:
|
||||||
|
The directive's _selector_ is typically the directive's **attribute name** in square brackets, `[myUnless]`.
|
||||||
The directive's _selector_ is typically the directive's **attribute name** in square brackets.`[myUnless]`.
|
|
||||||
The brackets define a CSS
|
The brackets define a CSS
|
||||||
<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors" target="_blank" title="MDN: Attribute selectors">attribute selector</a>.
|
<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors" target="_blank" title="MDN: Attribute selectors">attribute selector</a>.
|
||||||
|
|
||||||
|
@ -516,19 +468,12 @@ and access the _view container_ through a
|
||||||
[`ViewContainerRef`](../api/core/index/ViewContainerRef-class.html "API: ViewContainerRef").
|
[`ViewContainerRef`](../api/core/index/ViewContainerRef-class.html "API: ViewContainerRef").
|
||||||
|
|
||||||
You inject both in the directive constructor as private variables of the class.
|
You inject both in the directive constructor as private variables of the class.
|
||||||
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/unless.directive.ts' region='ctor'}
|
|
||||||
|
|
||||||
### The _myUnless_ property
|
### The _myUnless_ property
|
||||||
|
|
||||||
The directive consumer expects to bind a true/false condition to `[myUnless]`.
|
The directive consumer expects to bind a true/false condition to `[myUnless]`.
|
||||||
That means the directive needs a `myUnless` property, decorated with `@Input`
|
That means the directive needs a `myUnless` property, decorated with `@Input`
|
||||||
|
|
||||||
Read about `@Input` in the [_Template Syntax_](template-syntax.html#inputs-outputs) guide.
|
Read about `@Input` in the [_Template Syntax_](template-syntax.html#inputs-outputs) guide.
|
||||||
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/unless.directive.ts' region='set'}
|
|
||||||
|
|
||||||
Angular sets the `myUnless` property whenever the value of the condition changes.
|
Angular sets the `myUnless` property whenever the value of the condition changes.
|
||||||
Because the `myUnless` property does work, it needs a setter.
|
Because the `myUnless` property does work, it needs a setter.
|
||||||
|
|
||||||
|
@ -541,18 +486,12 @@ clear the container which also destroys the view.
|
||||||
Nobody reads the `myUnless` property so it doesn't need a getter.
|
Nobody reads the `myUnless` property so it doesn't need a getter.
|
||||||
|
|
||||||
The completed directive code looks like this:
|
The completed directive code looks like this:
|
||||||
|
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/unless.directive.ts' region='no-docs'}
|
|
||||||
|
|
||||||
Add this directive to the `!{_declsVsDirectives}` !{_array} of the !{_AppModuleVsAppComp}.
|
Add this directive to the `!{_declsVsDirectives}` !{_array} of the !{_AppModuleVsAppComp}.
|
||||||
|
|
||||||
Then create some HTML to try it.
|
Then create some HTML to try it.
|
||||||
|
|
||||||
{@example 'structural-directives/ts/src/app/app.component.html' region='myUnless'}
|
|
||||||
|
|
||||||
When the `condition` is falsy, the top (A) paragraph appears and the bottom (B) paragraph disappears.
|
When the `condition` is falsy, the top (A) paragraph appears and the bottom (B) paragraph disappears.
|
||||||
When the `condition` is truthy, the top (A) paragraph is removed and the bottom (B) paragraph appears.
|
When the `condition` is truthy, the top (A) paragraph is removed and the bottom (B) paragraph appears.
|
||||||
|
|
||||||
<figure class='image-display'>
|
<figure class='image-display'>
|
||||||
<img src='assets/images/devguide/structural-directives/unless-anim.gif' alt="UnlessDirective in action"> </img>
|
<img src='assets/images/devguide/structural-directives/unless-anim.gif' alt="UnlessDirective in action"> </img>
|
||||||
</figure>
|
</figure>
|
||||||
|
@ -562,9 +501,10 @@ When the `condition` is truthy, the top (A) paragraph is removed and the bottom
|
||||||
{@a summary}
|
{@a summary}
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
You can both try and download the source code for this guide in the <live-example></live-example>.
|
You can both try and download the source code for this guide in the <live-example></live-example>.
|
||||||
|
|
||||||
Here is the source from the `app/` folder.
|
Here is the source from the `src/app/` folder.
|
||||||
|
|
||||||
<md-tab-group>
|
<md-tab-group>
|
||||||
|
|
||||||
|
@ -606,9 +546,10 @@ Here is the source from the `app/` folder.
|
||||||
</md-tab-group>
|
</md-tab-group>
|
||||||
|
|
||||||
You learned
|
You learned
|
||||||
|
|
||||||
* that structural directives manipulate HTML layout.
|
* that structural directives manipulate HTML layout.
|
||||||
* to use [`<ng-container>`](#ngcontainer) as a grouping element when there is no suitable host element.
|
* to use [`<ng-container>`](#ngcontainer) as a grouping element when there is no suitable host element.
|
||||||
* that the angular "de-sugars" [asterisk (\*) syntax](#asterisk) into a `<template>`.
|
* that the Angular desugars [asterisk (*) syntax](#asterisk) into a `<template>`.
|
||||||
* how that works for the `NgIf`, `NgFor` and `NgSwitch` built-in directives.
|
* how that works for the `NgIf`, `NgFor` and `NgSwitch` built-in directives.
|
||||||
* about the [_microsyntax_](#microsyntax) that expands into a [`<template>`](#template).
|
* about the [_microsyntax_](#microsyntax) that expands into a [`<template>`](#template).
|
||||||
* to write a [custom structural directive](#unless), `UnlessDirective`.
|
* to write a [custom structural directive](#unless), `UnlessDirective`.
|
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,7 @@
|
||||||
TypeScript to JavaScript
|
TypeScript to JavaScript
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Convert Angular TypeScript examples into ES6 and ES5 JavaScript
|
Convert Angular TypeScript examples into ES6 and ES5 JavaScript.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
Anything you can do with Angular in _TypeScript_, you can also do
|
Anything you can do with Angular in _TypeScript_, you can also do
|
||||||
|
@ -40,7 +40,7 @@ code shown in this cookbook.**
|
||||||
|
|
||||||
_TypeScript_
|
_TypeScript_
|
||||||
<a href="https://www.typescriptlang.org" target="_blank" title='"TypeScript is a typed, superset of JavaScript"'>is a typed superset of _ES6 JavaScript_</a>.
|
<a href="https://www.typescriptlang.org" target="_blank" title='"TypeScript is a typed, superset of JavaScript"'>is a typed superset of _ES6 JavaScript_</a>.
|
||||||
_ES6 JavaScript_ is a superset of _ES5 JavaScript_. _ES5_ is the kind of JavaScript that runs natively in all modern browsers.
|
_ES6 JavaScript_ is a superset of _ES5 JavaScript_. _ES5_ is the kind of JavaScript that runs natively in all modern browsers.
|
||||||
The transformation of _TypeScript_ code all the way down to _ES5_ code can be seen as "shedding" features.
|
The transformation of _TypeScript_ code all the way down to _ES5_ code can be seen as "shedding" features.
|
||||||
|
|
||||||
The downgrade progression is
|
The downgrade progression is
|
|
@ -2,7 +2,7 @@
|
||||||
Visual Studio 2015 QuickStart
|
Visual Studio 2015 QuickStart
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Use Visual Studio 2015 with the QuickStart files
|
Use Visual Studio 2015 with the QuickStart files.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
<a id="top"></a>Some developers prefer Visual Studio as their Integrated Development Environment (IDE).
|
<a id="top"></a>Some developers prefer Visual Studio as their Integrated Development Environment (IDE).
|
|
@ -2,7 +2,7 @@
|
||||||
Webpack: an introduction
|
Webpack: an introduction
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
Create Angular applications with a Webpack based tooling
|
Create Angular applications with a Webpack based tooling.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ The development build relies on the Webpack development server, configured near
|
||||||
|
|
||||||
Although you tell Webpack to put output bundles in the `dist` folder,
|
Although you tell Webpack to put output bundles in the `dist` folder,
|
||||||
the dev server keeps all bundles in memory; it doesn't write them to disk.
|
the dev server keeps all bundles in memory; it doesn't write them to disk.
|
||||||
You won't find any files in the `dist` folder (at least not any generated from `this development build`).
|
You won't find any files in the `dist` folder (at least not any generated from *this development build*).
|
||||||
|
|
||||||
|
|
||||||
The `HtmlWebpackPlugin` (added in `webpack.common.js`) use the *publicPath* and the *filename* settings to generate
|
The `HtmlWebpackPlugin` (added in `webpack.common.js`) use the *publicPath* and the *filename* settings to generate
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
The Hero Editor
|
The Hero Editor
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
We build a simple hero editor
|
We build a simple hero editor.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
## Setup to develop locally
|
## Setup to develop locally
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Master/Detail
|
Master/Detail
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
We build a master/detail page with a list of heroes
|
We build a master/detail page with a list of heroes.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
Our story needs more heroes.
|
Our story needs more heroes.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Multiple Components
|
Multiple Components
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
We refactor the master/detail view into separate components
|
We refactor the master/detail view into separate components.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
Our app is growing.
|
Our app is growing.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Services
|
Services
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
We create a reusable service to manage our hero data calls
|
We create a reusable service to manage our hero data calls.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
The Tour of Heroes is evolving and we anticipate adding more components in the near future.
|
The Tour of Heroes is evolving and we anticipate adding more components in the near future.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Routing
|
Routing
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
We add the Angular Router and learn to navigate among the views
|
We add the Angular Router and learn to navigate among the views.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
We received new requirements for our Tour of Heroes application:
|
We received new requirements for our Tour of Heroes application:
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
HTTP
|
HTTP
|
||||||
|
|
||||||
@intro
|
@intro
|
||||||
We convert our service and components to use Angular's HTTP service
|
We convert our service and components to use Angular's HTTP service.
|
||||||
|
|
||||||
@description
|
@description
|
||||||
Our stakeholders appreciate our progress.
|
Our stakeholders appreciate our progress.
|
||||||
|
|
Loading…
Reference in New Issue