docs(aio): fix paths to images

This commit is contained in:
Peter Bacon Darwin 2017-03-06 10:43:33 +00:00 committed by Igor Minar
parent 0d63e2a586
commit b70c881c00
35 changed files with 965 additions and 908 deletions

View File

@ -2,7 +2,7 @@
AngularJS to Angular Quick Reference
@intro
Learn how AngularJS concepts and techniques map to Angular
Learn how AngularJS concepts and techniques map to Angular.
@description
@ -16,16 +16,16 @@ by mapping AngularJS syntax to the equivalent Angular syntax.
**See the Angular syntax in this <live-example name="cb-ajs-quick-reference"></live-example>**.
## Contents
This page covers:
* [Template basics](#template-basics) - binding and local variables.
* [Template directives](#template-directives) - built-in directives `ngIf` and `ngClass`.
* [Template basics](#template-basics)&mdash;binding and local variables.
* [Filters/pipes](#filters-pipes) - built-in *filters*, known as *pipes* in Angular.
* [Template directives](#template-directives)&mdash;built-in directives `ngIf` and `ngClass`.
* [Modules/controllers/components](#controllers-components) - *modules* in Angular are slightly different from *modules* in AngularJS, and *controllers* are *components* in Angular.
* [Filters/pipes](#filters-pipes)&mdash;built-in *filters*, known as *pipes* in Angular.
* [Style sheets](#style-sheets) - more options for CSS than in AngularJS.
* [Modules/controllers/components](#controllers-components)&mdash;*modules* in Angular are slightly different from *modules* in AngularJS, and *controllers* are *components* in Angular.
* [Style sheets](#style-sheets)&mdash;more options for CSS than in AngularJS.
## Template basics
Templates are the user-facing part of an Angular application and are written in HTML.
@ -86,7 +86,8 @@ The following table lists some of the key AngularJS template features with their
The context of the binding is implied and is always the
associated component, so it needs no reference variable.
For more information, see the [Interpolation](../guide/template-syntax.html#interpolation) section of the Template Syntax page.
For more information, see the [Interpolation](../guide/template-syntax.html#interpolation)
section of the [Template Syntax](../guide/template-syntax.html) page.
</td>
@ -116,7 +117,7 @@ The following table lists some of the key AngularJS template features with their
Many (but not all) of the built-in filters from AngularJS are
built-in pipes in Angular.
For more information, see the heading [Filters/pipes](#filters-pipes) below.
For more information, see [Filters/pipes](#filters-pipes) below.
</td>
@ -144,7 +145,8 @@ The following table lists some of the key AngularJS template features with their
Angular has true template input variables that are explicitly defined using the `let` keyword.
For more information, see the [ngFor micro-syntax](../guide/template-syntax.html#ngForMicrosyntax) section of the Template Syntax page.
For more information, see the [ngFor micro-syntax](../guide/template-syntax.html#microsyntax)
section of the [Template Syntax](../guide/template-syntax.html) page.
</td>
@ -260,7 +262,8 @@ The following are some of the key AngularJS built-in directives and their equiva
Angular also has **class binding**, which is a good way to add or remove a single class,
as shown in the third example.
For more information see the [Attribute, Class, and Style Bindings](../guide/template-syntax.html#other-bindings) section of the Template Syntax page.
For more information see the [Attribute, class, and style bindings](../guide/template-syntax.html#other-bindings)
section of the [Template Syntax](../guide/template-syntax.html) page.
</td>
@ -287,7 +290,7 @@ The following are some of the key AngularJS built-in directives and their equiva
<td>
### bind to the `click` event
### Bind to the `click` event
{@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='event-binding'}
@ -306,7 +309,8 @@ The following are some of the key AngularJS built-in directives and their equiva
For a list of DOM events, see: https://developer.mozilla.org/en-US/docs/Web/Events.
For more information, see the [Event Binding](../guide/template-syntax.html#event-binding) section of the Template Syntax page.
For more information, see the [Event binding](../guide/template-syntax.html#event-binding)
section of the [Template Syntax](../guide/template-syntax.html) page.
</td>
@ -354,7 +358,7 @@ The following are some of the key AngularJS built-in directives and their equiva
<td>
### bind to the `hidden` property
### Bind to the `hidden` property
In Angular, you use property binding; there is no built-in *hide* directive.
For more information, see [ng-show](#ng-show).
</td>
@ -385,20 +389,22 @@ The following are some of the key AngularJS built-in directives and their equiva
<td>
### bind to the `href` property
### Bind to the `href` property
{@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='href'}
Angular, uses property binding; there is no built-in *href* directive.
Angular uses property binding; there is no built-in *href* directive.
Place the element's `href` property in square brackets and set it to a quoted template expression.
For more information on property binding, see [Template Syntax](../guide/template-syntax.html#property-binding).
For more information see the [Property binding](../guide/template-syntax.html#property-binding)
section of the [Template Syntax](../guide/template-syntax.html) page.
In Angular, `href` is no longer used for routing. Routing uses `routerLink`, as shown in the third example.
In Angular, `href` is no longer used for routing. Routing uses `routerLink`, as shown in the following example.
{@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='router-link'}
For more information on routing, see [Routing & Navigation](../guide/router.html#router-link).
For more information on routing, see the [RouterLink binding](../guide/router.html#router-link)
section of the [Routing & Navigation](../guide/router.html) page.
</td>
@ -417,7 +423,7 @@ The following are some of the key AngularJS built-in directives and their equiva
In AngularJS, the `ng-if` directive removes or recreates a portion of the DOM,
based on an expression. If the expression is false, the element is removed from the DOM.
In this example, the `table` element is removed from the DOM unless the `movies` array has a length greater than zero.
In this example, the `<table>` element is removed from the DOM unless the `movies` array has a length greater than zero.
</td>
@ -426,9 +432,10 @@ The following are some of the key AngularJS built-in directives and their equiva
{@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.html' region='ngIf'}
The `*ngIf` directive in Angular works the same as the `ng-if` directive in AngularJS. It removes or recreates a portion of the DOM based on an expression.
The `*ngIf` directive in Angular works the same as the `ng-if` directive in AngularJS. It removes
or recreates a portion of the DOM based on an expression.
In this example, the `table` element is removed from the DOM unless the `movies` array has a length.
In this example, the `<table>` element is removed from the DOM unless the `movies` array has a length.
The (*) before `ngIf` is required in this example.
For more information, see [Structural Directives](../guide/structural-directives.html).
@ -459,7 +466,9 @@ The following are some of the key AngularJS built-in directives and their equiva
In Angular, **two-way binding** is denoted by `[()]`, descriptively referred to as a "banana in a box". This syntax is a shortcut for defining both property binding (from the component to the view)
and event binding (from the view to the component), thereby providing two-way binding.
For more information on two-way binding with ngModel, see [Template Syntax](../guide/template-syntax.html#ngModel).
For more information on two-way binding with `ngModel`, see the [NgModel&mdash;Two-way binding to
form elements with `[(ngModel)]`](../guide/template-syntax.html#ngModel)
section of the [Template Syntax](../guide/template-syntax.html) page.
</td>
@ -477,7 +486,7 @@ The following are some of the key AngularJS built-in directives and their equiva
In AngularJS, the `ng-repeat` directive repeats the associated DOM element
for each item in the specified collection.
In this example, the table row (`tr`) element repeats for each movie object in the collection of movies.
In this example, the table row (`<tr>`) element repeats for each movie object in the collection of movies.
</td>
@ -486,8 +495,9 @@ The following are some of the key AngularJS built-in directives and their equiva
{@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.html' region='ngFor'}
The `*ngFor` directive in Angular is similar to the `ng-repeat` directive in AngularJS. It repeats the associated DOM element for each item in the specified collection.
More accurately, it turns the defined element (`tr` in this example) and its contents into a template and
The `*ngFor` directive in Angular is similar to the `ng-repeat` directive in AngularJS. It repeats
the associated DOM element for each item in the specified collection.
More accurately, it turns the defined element (`<tr>` in this example) and its contents into a template and
uses that template to instantiate a view for each item in the list.
Notice the other syntax differences:
@ -515,24 +525,25 @@ The following are some of the key AngularJS built-in directives and their equiva
In AngularJS, the `ng-show` directive shows or hides the associated DOM element, based on
an expression.
In this example, the `div` element is shown if the `favoriteHero` variable is truthy.
In this example, the `<div>` element is shown if the `favoriteHero` variable is truthy.
</td>
<td>
### bind to the `hidden` property
### Bind to the `hidden` property
{@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.html' region='hidden'}
Angular, uses property binding; there is no built-in *show* directive.
Angular uses property binding; there is no built-in *show* directive.
For hiding and showing elements, bind to the HTML `hidden` property.
To conditionally display an element, place the element's `hidden` property in square brackets and
set it to a quoted template expression that evaluates to the *opposite* of *show*.
In this example, the `div` element is hidden if the `favoriteHero` variable is not truthy.
In this example, the `<div>` element is hidden if the `favoriteHero` variable is not truthy.
For more information on property binding, see [Template Syntax](../guide/template-syntax.html#property-binding).
For more information on property binding, see the [Property binding](../guide/template-syntax.html#property-binding)
section of the [Template Syntax](../guide/template-syntax.html) page.
</td>
@ -554,14 +565,15 @@ The following are some of the key AngularJS built-in directives and their equiva
<td>
### bind to the `src` property
### Bind to the `src` property
{@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='src'}
Angular, uses property binding; there is no built-in *src* directive.
Angular uses property binding; there is no built-in *src* directive.
Place the `src` property in square brackets and set it to a quoted template expression.
For more information on property binding, see [Template Syntax](../guide/template-syntax.html#property-binding).
For more information on property binding, see the [Property binding](../guide/template-syntax.html#property-binding)
section of the [Template Syntax](../guide/template-syntax.html) page.
</td>
@ -578,7 +590,7 @@ The following are some of the key AngularJS built-in directives and their equiva
In AngularJS, the `ng-style` directive sets a CSS style on an HTML element
based on an expression. That expression is often a key-value control object with each
key of the object defined as a CSS style name, and each value defined as an expression
key of the object defined as a CSS property, and each value defined as an expression
that evaluates to a value appropriate for the style.
In the example, the `color` style is set to the current value of the `colorPreference` variable.
@ -596,9 +608,11 @@ The following are some of the key AngularJS built-in directives and their equiva
Angular also has **style binding**, which is good way to set a single style. This is shown in the second example.
For more information on style binding, see [Template Syntax](../guide/template-syntax.html#style-binding).
For more information on style binding, see the [Style binding](../guide/template-syntax.html#style-binding) section of the
[Template Syntax](../guide/template-syntax.html) page.
For more information on the ngStyle directive, see [Template Syntax](../guide/template-syntax.html#ngStyle).
For more information on the `ngStyle` directive, see [NgStyle](../guide/template-syntax.html#ngStyle)
section of the [Template Syntax](../guide/template-syntax.html) page.
</td>
@ -650,7 +664,8 @@ The following are some of the key AngularJS built-in directives and their equiva
The (*) before `ngSwitchCase` and `ngSwitchDefault` is required in this example.
For more information on the ngSwitch directive, see [Template Syntax](../guide/template-syntax.html#ngSwitch).
For more information, see [The NgSwitch directives](../guide/template-syntax.html#ngSwitch)
section of the [Template Syntax](../guide/template-syntax.html) page.
</td>
@ -665,7 +680,7 @@ The following are some of the key AngularJS built-in directives and their equiva
{@a filters-pipes}
## Filters/pipes
Angular **pipes** provide formatting and transformation for data in our template, similar to AngularJS **filters**.
Angular **pipes** provide formatting and transformation for data in the template, similar to AngularJS **filters**.
Many of the built-in filters in AngularJS have corresponding pipes in Angular.
For more information on pipes, see [Pipes](../guide/pipes.html).
@ -704,7 +719,7 @@ For more information on pipes, see [Pipes](../guide/pipes.html).
&lt;td>{{movie.price | currency}}&lt;/td>
</code-example>
Formats a number as a currency.
Formats a number as currency.
</td>
@ -949,17 +964,19 @@ The Angular code is shown using TypeScript.
}());
</code-example>
In AngularJS, you often defined an immediately invoked function expression (or IIFE) around your controller code.
This kept your controller code out of the global namespace.
In AngularJS, an immediately invoked function expression (or IIFE) around controller code
keeps it out of the global namespace.
</td>
<td>
### none
You don't need to worry about this in Angular because you use ES 2015 modules
and modules handle the namespacing for you.
This is a nonissue in Angular because ES 2015 modules
handle the namespacing for you.
For more information on modules, see [Architecture Overview](../guide/architecture.html#module).
For more information on modules, see the [Modules](../guide/architecture.html#modules) section of the
[Architecture Overview](../guide/architecture.html).
</td>
@ -974,7 +991,8 @@ The Angular code is shown using TypeScript.
angular.module("movieHunter", ["ngRoute"]);
</code-example>
In AngularJS, an Angular module keeps track of controllers, services, and other code. The second argument defines the list of other modules that this module depends upon.
In AngularJS, an Angular module keeps track of controllers, services, and other code.
The second argument defines the list of other modules that this module depends upon.
</td>
@ -987,7 +1005,7 @@ The Angular code is shown using TypeScript.
- `imports`: specifies the list of other modules that this module depends upon
- `declaration`: keeps track of your components, pipes, and directives.
For more information on modules, see [Angular Modules](../guide/ngmodule.html).
For more information on modules, see [Angular Modules (NgModule)](../guide/ngmodule.html).
</td>
@ -1006,7 +1024,7 @@ The Angular code is shown using TypeScript.
MovieListCtrl]);
</code-example>
AngularJS, has code in each controller that looks up an appropriate Angular module
AngularJS has code in each controller that looks up an appropriate Angular module
and registers the controller with that module.
The first argument is the controller name. The second argument defines the string names of
@ -1015,17 +1033,18 @@ The Angular code is shown using TypeScript.
<td>
### Component Decorator
### Component decorator
{@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.ts' region='component'}
Angular, adds a decorator to the component class to provide any required metadata.
The Component decorator declares that the class is a component and provides metadata about
Angular adds a decorator to the component class to provide any required metadata.
The `@Component` decorator declares that the class is a component and provides metadata about
that component such as its selector (or tag) and its template.
This is how you associate a template with code, which is defined in the component class.
This is how you associate a template with logic, which is defined in the component class.
For more information, see the [Components](../guide/architecture.html#components) section of the Architecture Overview page.
For more information, see the [Components](../guide/architecture.html#components)
section of the [Architecture Overview](../guide/architecture.html) page.
</td>
@ -1054,7 +1073,8 @@ The Angular code is shown using TypeScript.
NOTE: If you are using TypeScript with AngularJS, you must use the `export` keyword to export the component class.
For more information, see the [Components](../guide/architecture.html#components) section of the Architecture Overview page.
For more information, see the [Components](../guide/architecture.html#components)
section of the [Architecture Overview](../guide/architecture.html) page.
</td>
@ -1088,7 +1108,8 @@ The Angular code is shown using TypeScript.
This example injects a `MovieService`.
The first parameter's TypeScript type tells Angular what to inject, even after minification.
For more information, see the [Dependency Injection](../guide/architecture.html#dependency-injection) section of the Architecture Overview.
For more information, see the [Dependency injection](../guide/architecture.html#dependency-injection)
section of the [Architecture Overview](../guide/architecture.html).
</td>

View File

@ -615,9 +615,9 @@ The `source-map-explorer` analyzes the source map generated with the bundle and
showing exactly which application and Angular modules and classes are included in the bundle.
Here's the map for _Tour of Heroes_.
<a href="/resources/images/cookbooks/aot-compiler/toh6-bundle.png" target="_blank" title="View larger image">
<a href="assets/images/cookbooks/aot-compiler/toh6-bundle.png" target="_blank" title="View larger image">
<figure class='image-display'>
<img src="/resources/images/cookbooks/aot-compiler/toh6-bundle.png" alt="TOH-6-bundle"> </img>
<img src="assets/images/cookbooks/aot-compiler/toh6-bundle.png" alt="TOH-6-bundle"> </img>
</figure>
</a>

View File

@ -44,7 +44,7 @@ and each iteration's `hero` instance to the child's `hero` property.
The running application displays three heroes:
<figure class='image-display'>
<img src="/resources/images/cookbooks/component-communication/parent-to-child.png" alt="Parent-to-child"> </img>
<img src="assets/images/cookbooks/component-communication/parent-to-child.png" alt="Parent-to-child"> </img>
</figure>
### Test it
@ -73,7 +73,7 @@ Here's the `NameParentComponent` demonstrating name variations including a name
<figure class='image-display'>
<img src="/resources/images/cookbooks/component-communication/setter.png" alt="Parent-to-child-setter"> </img>
<img src="assets/images/cookbooks/component-communication/setter.png" alt="Parent-to-child-setter"> </img>
</figure>
### Test it
@ -103,7 +103,7 @@ The `VersionParentComponent` supplies the `minor` and `major` values and binds b
Here's the output of a button-pushing sequence:
<figure class='image-display'>
<img src="/resources/images/cookbooks/component-communication/parent-to-child-on-changes.gif" alt="Parent-to-child-onchanges"> </img>
<img src="assets/images/cookbooks/component-communication/parent-to-child-on-changes.gif" alt="Parent-to-child-onchanges"> </img>
</figure>
### Test it
@ -140,7 +140,7 @@ The framework passes the event argument &mdash; represented by `$event` &mdash;
and the method processes it:
<figure class='image-display'>
<img src="/resources/images/cookbooks/component-communication/child-to-parent.gif" alt="Child-to-parent"> </img>
<img src="assets/images/cookbooks/component-communication/child-to-parent.gif" alt="Child-to-parent"> </img>
</figure>
### Test it
@ -185,7 +185,7 @@ use interpolation to display the child's `seconds` property.
Here we see the parent and child working together.
<figure class='image-display'>
<img src="/resources/images/cookbooks/component-communication/countdown-timer-anim.gif" alt="countdown timer"> </img>
<img src="assets/images/cookbooks/component-communication/countdown-timer-anim.gif" alt="countdown timer"> </img>
</figure>
@ -287,7 +287,7 @@ the parent `MissionControlComponent` and the `AstronautComponent` children,
facilitated by the service:
<figure class='image-display'>
<img src="/resources/images/cookbooks/component-communication/bidirectional-service.gif" alt="bidirectional-service"> </img>
<img src="assets/images/cookbooks/component-communication/bidirectional-service.gif" alt="bidirectional-service"> </img>
</figure>
### Test it

View File

@ -122,7 +122,7 @@ The author simply declared what was needed in the constructor (`LoggerService` a
Once all the dependencies are in place, the `AppComponent` displays the user information:
<figure class='image-display'>
<img src="/resources/images/cookbooks/dependency-injection/logged-in-user.png" alt="Logged In User"> </img>
<img src="assets/images/cookbooks/dependency-injection/logged-in-user.png" alt="Logged In User"> </img>
</figure>
### *@Injectable()*
@ -233,7 +233,7 @@ And the template displays this data-bound property.
Find this example in <live-example name="cb-dependency-injection">live code</live-example>
and confirm that the three `HeroBioComponent` instances have their own cached hero data.
<figure class='image-display'>
<img src="/resources/images/cookbooks/dependency-injection/hero-bios.png" alt="Bios"> </img>
<img src="assets/images/cookbooks/dependency-injection/hero-bios.png" alt="Bios"> </img>
</figure>
@ -280,7 +280,7 @@ placing it in the `<ng-content>` slot of the `HeroBioComponent` template:
It looks like this, with the hero's telephone number from `HeroContactComponent` projected above the hero description:
<figure class='image-display'>
<img src="/resources/images/cookbooks/dependency-injection/hero-bio-and-content.png" alt="bio and contact"> </img>
<img src="assets/images/cookbooks/dependency-injection/hero-bio-and-content.png" alt="bio and contact"> </img>
</figure>
Here's the `HeroContactComponent` which demonstrates the qualifying decorators that we're talking about in this section:
@ -304,14 +304,14 @@ Thanks to `@Optional()`, Angular sets the `loggerService` to null and the rest o
We'll come back to the `elementRef` property shortly.Here's the `HeroBiosAndContactsComponent` in action.
<figure class='image-display'>
<img src="/resources/images/cookbooks/dependency-injection/hero-bios-and-contacts.png" alt="Bios with contact into"> </img>
<img src="assets/images/cookbooks/dependency-injection/hero-bios-and-contacts.png" alt="Bios with contact into"> </img>
</figure>
If we comment out the `@Host()` decorator, Angular now walks up the injector ancestor tree
until it finds the logger at the `AppComponent` level. The logger logic kicks in and the hero display updates
with the gratuitous "!!!", indicating that the logger was found.
<figure class='image-display'>
<img src="/resources/images/cookbooks/dependency-injection/hero-bio-contact-no-host.png" alt="Without @Host"> </img>
<img src="assets/images/cookbooks/dependency-injection/hero-bio-contact-no-host.png" alt="Without @Host"> </img>
</figure>
On the other hand, if we restore the `@Host()` decorator and comment out `@Optional`,
@ -343,7 +343,7 @@ first without a value (yielding the default color) and then with an assigned col
The following image shows the effect of mousing over the `<hero-bios-and-contacts>` tag.
<figure class='image-display'>
<img src="/resources/images/cookbooks/dependency-injection/highlight.png" alt="Highlighted bios"> </img>
<img src="assets/images/cookbooks/dependency-injection/highlight.png" alt="Highlighted bios"> </img>
</figure>
<a id="providers"></a>
@ -394,7 +394,7 @@ We need other ways to deliver dependency values and that means we need other way
The `HeroOfTheMonthComponent` example demonstrates many of the alternatives and why we need them.
<figure class='image-display'>
<img src="/resources/images/cookbooks/dependency-injection/hero-of-month.png" alt="Hero of the month" width="300px"> </img>
<img src="assets/images/cookbooks/dependency-injection/hero-of-month.png" alt="Hero of the month" width="300px"> </img>
</figure>
It's visually simple: a few properties and the output of a logger. The code behind it gives us plenty to talk about.
@ -493,14 +493,14 @@ We want to shrink that API surface to just the two members exposed by the `Minim
The constructor's `logger` parameter is typed as `MinimalLogger` so only its two members are visible in TypeScript:
<figure class='image-display'>
<img src="/resources/images/cookbooks/dependency-injection/minimal-logger-intellisense.png" alt="MinimalLogger restricted API"> </img>
<img src="assets/images/cookbooks/dependency-injection/minimal-logger-intellisense.png" alt="MinimalLogger restricted API"> </img>
</figure>
Angular actually sets the `logger` parameter to the injector's full version of the `LoggerService`
which happens to be the `DateLoggerService` thanks to the override provider registered previously via `useClass`.
The following image, which displays the logging date, confirms the point:
<figure class='image-display'>
<img src="/resources/images/cookbooks/dependency-injection/date-logger-entry.png" alt="DateLoggerService entry" width="300px"> </img>
<img src="assets/images/cookbooks/dependency-injection/date-logger-entry.png" alt="DateLoggerService entry" width="300px"> </img>
</figure>
@ -641,7 +641,7 @@ In this contrived example, `SortedHeroesComponent` inherits from `HeroesBaseComp
to display a *sorted* list of heroes.
<figure class='image-display'>
<img src="/resources/images/cookbooks/dependency-injection/sorted-heroes.png" alt="Sorted Heroes"> </img>
<img src="assets/images/cookbooks/dependency-injection/sorted-heroes.png" alt="Sorted Heroes"> </img>
</figure>
The `HeroesBaseComponent` could stand on its own.
@ -783,7 +783,7 @@ The [*forwardRef*](#forwardref) breaks the circular reference we just created by
Here's *Alex* and family in action:
<figure class='image-display'>
<img src="/resources/images/cookbooks/dependency-injection/alex.png" alt="Alex in action"> </img>
<img src="assets/images/cookbooks/dependency-injection/alex.png" alt="Alex in action"> </img>
</figure>
@ -834,7 +834,7 @@ which *is* what parent means.
Here's *Alice*, *Barry* and family in action:
<figure class='image-display'>
<img src="/resources/images/cookbooks/dependency-injection/alice.png" alt="Alice in action"> </img>
<img src="assets/images/cookbooks/dependency-injection/alice.png" alt="Alice in action"> </img>
</figure>

View File

@ -133,6 +133,6 @@ Two sample components and the `AdComponent` interface are shown below:
The final ad banner looks like this:
<figure class='image-display'>
<img src="/resources/images/cookbooks/dynamic-component-loader/ads.gif" alt="Ads"> </img>
<img src="assets/images/cookbooks/dynamic-component-loader/ads.gif" alt="Ads"> </img>
</figure>

View File

@ -162,7 +162,7 @@ This proves that any user input is bound back to the data model.
Saving and retrieving the data is an exercise for another time.
The final form looks like this:
<figure class='image-display'>
<img src="/resources/images/cookbooks/dynamic-form/dynamic-form.png" alt="Dynamic-Form"> </img>
<img src="assets/images/cookbooks/dynamic-form/dynamic-form.png" alt="Dynamic-Form"> </img>
</figure>
[Back to top](#top)

View File

@ -23,7 +23,7 @@ This cookbook explains how to do it.**See the <live-example name="cb-set-documen
<td>
<img src='/resources/images/devguide/plunker-switch-to-editor-button.png' width="200px" height="70px" alt="pop out the window" align="right"> </img> <br> </br> <img src='/resources/images/devguide/plunker-separate-window-button.png' width="200px" height="47px" alt="pop out the window" align="right"> </img>
<img src='assets/images/devguide/plunker-switch-to-editor-button.png' width="200px" height="70px" alt="pop out the window" align="right"> </img> <br> </br> <img src='assets/images/devguide/plunker-separate-window-button.png' width="200px" height="47px" alt="pop out the window" align="right"> </img>
</td>
@ -64,7 +64,7 @@ Let's inject the `Title` service into the root `AppComponent` and expose a binda
We bind that method to three anchor tags and, voilà!
<figure class='image-display'>
<img src="/resources/images/cookbooks/set-document-title/set-title-anim.gif" alt="Set title"> </img>
<img src="assets/images/cookbooks/set-document-title/set-title-anim.gif" alt="Set title"> </img>
</figure>
Here's the complete solution

View File

@ -48,7 +48,7 @@ The examples in this page are available as a <live-example></live-example>.
## Quickstart example: Transitioning between two states
<figure>
<img src="/resources/images/devguide/animations/animation_basic_click.gif" alt="A simple transition animation" align="right" style="width:220px;margin-left:20px"> </img>
<img src="assets/images/devguide/animations/animation_basic_click.gif" alt="A simple transition animation" align="right" style="width:220px;margin-left:20px"> </img>
</figure>
You can build a simple animation that transitions an element between two states
@ -121,7 +121,7 @@ controls the timing of switching between one set of styles and the next:
<figure class='image-display'>
<img src="/resources/images/devguide/animations/ng_animate_transitions_inactive_active.png" alt="In Angular animations you define states and transitions between states" width="400"> </img>
<img src="assets/images/devguide/animations/ng_animate_transitions_inactive_active.png" alt="In Angular animations you define states and transitions between states" width="400"> </img>
</figure>
If several transitions have the same timing configuration, you can combine
@ -154,7 +154,7 @@ transitions that apply regardless of which state the animation is in. For exampl
* The `* => *` transition applies when *any* change between two states takes place.
<figure class='image-display'>
<img src="/resources/images/devguide/animations/ng_animate_transitions_inactive_active_wildcards.png" alt="The wildcard state can be used to match many different transitions at once" width="400"> </img>
<img src="assets/images/devguide/animations/ng_animate_transitions_inactive_active_wildcards.png" alt="The wildcard state can be used to match many different transitions at once" width="400"> </img>
</figure>
### The `void` state
@ -168,14 +168,14 @@ For example the `* => void` transition applies when the element leaves the view,
regardless of what state it was in before it left.
<figure class='image-display'>
<img src="/resources/images/devguide/animations/ng_animate_transitions_void_in.png" alt="The void state can be used for enter and leave transitions" width="400"> </img>
<img src="assets/images/devguide/animations/ng_animate_transitions_void_in.png" alt="The void state can be used for enter and leave transitions" width="400"> </img>
</figure>
The wildcard state `*` also matches `void`.
## Example: Entering and leaving
<figure>
<img src="/resources/images/devguide/animations/animation_enter_leave.gif" alt="Enter and leave animations" align="right" style="width:250px;"> </img>
<img src="assets/images/devguide/animations/animation_enter_leave.gif" alt="Enter and leave animations" align="right" style="width:250px;"> </img>
</figure>
Using the `void` and `*` states you can define transitions that animate the
@ -184,6 +184,8 @@ entering and leaving of elements:
* Enter: `void => *`
* Leave: `* => void`
For example, in the `animations` !{_array} below there are two transitions that use
the `void => *` and `* => void` syntax to animate the element in and out of the view.
{@example 'animations/ts/src/app/hero-list-enter-leave.component.ts' region='animationdef'}
@ -201,7 +203,7 @@ These two common animations have their own aliases:
## Example: Entering and leaving from different states
<figure>
<img src="/resources/images/devguide/animations/animation_enter_leave_states.gif" alt="Enter and leave animations combined with state animations" align="right" style="width:200px"> </img>
<img src="assets/images/devguide/animations/animation_enter_leave_states.gif" alt="Enter and leave animations combined with state animations" align="right" style="width:200px"> </img>
</figure>
You can also combine this animation with the earlier state transition animation by
@ -217,7 +219,7 @@ is:
This gives you fine-grained control over each transition:
<figure class='image-display'>
<img src="/resources/images/devguide/animations/ng_animate_transitions_inactive_active_void.png" alt="This example transitions between active, inactive, and void states" width="400"> </img>
<img src="assets/images/devguide/animations/ng_animate_transitions_inactive_active_void.png" alt="This example transitions between active, inactive, and void states" width="400"> </img>
</figure>
@ -245,7 +247,7 @@ If you don't provide a unit when specifying dimension, Angular assumes the defau
## Automatic property calculation
<figure>
<img src="/resources/images/devguide/animations/animation_auto.gif" alt="Animation with automated height calculation" align="right" style="width:220px;margin-left:20px"> </img>
<img src="assets/images/devguide/animations/animation_auto.gif" alt="Animation with automated height calculation" align="right" style="width:220px;margin-left:20px"> </img>
</figure>
Sometimes you don't know the value of a dimensional style property until runtime.
@ -297,21 +299,22 @@ and the delay (or as the *second* value when there is no delay):
* Run for 200ms, with easing: `'0.2s ease-in-out'`
<figure>
<img src="/resources/images/devguide/animations/animation_timings.gif" alt="Animations with specific timings" align="right" style="width:220px;margin-left:20px"> </img>
<img src="assets/images/devguide/animations/animation_timings.gif" alt="Animations with specific timings" align="right" style="width:220px;margin-left:20px"> </img>
</figure>
### Example
Here are a couple of custom timings in action. Both enter and leave last for
200 milliseconds but they have different easings. The leave begins after a
slight delay:
200 milliseconds, that is `0.2s`, but they have different easings. The leave begins after a
slight delay of 10 milliseconds as specified in `'0.2s 10 ease-out'`:
{@example 'animations/ts/src/app/hero-list-timings.component.ts' region='animationdef'}
## Multi-step animations with keyframes
<figure>
<img src="/resources/images/devguide/animations/animation_multistep.gif" alt="Animations with some bounce implemented with keyframes" align="right" style="width:220px;margin-left:20px"> </img>
<img src="assets/images/devguide/animations/animation_multistep.gif" alt="Animations with some bounce implemented with keyframes" align="right" style="width:220px;margin-left:20px"> </img>
</figure>
Animation *keyframes* go beyond a simple transition to a more intricate animation
@ -336,7 +339,7 @@ spacing are automatically assigned. For example, three keyframes without predefi
offsets receive offsets `0`, `0.5`, and `1`.
## Parallel animation groups
<figure>
<img src="/resources/images/devguide/animations/animation_groups.gif" alt="Parallel animations with different timings, implemented with groups" align="right" style="width:220px;margin-left:20px"> </img>
<img src="assets/images/devguide/animations/animation_groups.gif" alt="Parallel animations with different timings, implemented with groups" align="right" style="width:220px;margin-left:20px"> </img>
</figure>
You've seen how to animate multiple style properties at the same time:
@ -358,7 +361,7 @@ One group animates the element transform and width; the other group animates the
A callback is fired when an animation is started and also when it is done.
In the keyframes example, you have a `trigger` called `@flyInOut`. There you can hook
In the keyframes example, you have a `trigger` called `@flyInOut`. You can hook
those callbacks like this:

View File

@ -151,7 +151,7 @@ This file is very stable. Once you've set it up, you may never change it again.
Your initial app has only a single module, the _root_ module.
As your app grows, you'll consider subdividing it into multiple "feature" modules,
so of which can be loaded later ("lazy loaded") if and when the user chooses
some of which can be loaded later ("lazy loaded") if and when the user chooses
to visit those features.
When you're ready to explore these possibilities, visit the [Angular Modules (NgModule)](ngmodule.html) guide.

View File

@ -17,7 +17,7 @@ Of course, there is more to it than this.
You'll learn the details in the pages that follow. For now, focus on the big picture.
<figure>
<img src="/resources/images/devguide/architecture/overview2.png" alt="overview" style="margin-left:-40px;" width="700"> </img>
<img src="assets/images/devguide/architecture/overview2.png" alt="overview" style="margin-left:-40px;" width="700"> </img>
</figure>
The architecture diagram identifies the eight main building blocks of an Angular application:
@ -41,13 +41,13 @@ Learn these building blocks, and you're on your way.
## Modules
<figure>
<img src="/resources/images/devguide/architecture/module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/architecture/module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px"> </img>
</figure>
### Angular libraries
<figure>
<img src="/resources/images/devguide/architecture/library-module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/architecture/library-module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px"> </img>
</figure>
@ -59,7 +59,7 @@ Learn these building blocks, and you're on your way.
## Components
<figure>
<img src="/resources/images/devguide/architecture/hero-component.png" alt="Component" align="left" style="width:200px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/architecture/hero-component.png" alt="Component" align="left" style="width:200px; margin-left:-40px;margin-right:10px"> </img>
</figure>
A _component_ controls a patch of screen called a *view*.
@ -87,7 +87,7 @@ Your app can take action at each moment in this lifecycle through optional [life
## Templates
<figure>
<img src="/resources/images/devguide/architecture/template.png" alt="Template" align="left" style="width:200px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/architecture/template.png" alt="Template" align="left" style="width:200px; margin-left:-40px;margin-right:10px"> </img>
</figure>
You define a component's view with its companion **template**. A template is a form of HTML
@ -110,7 +110,7 @@ hero that the user selects from the list presented by the `HeroListComponent`.
The `HeroDetailComponent` is a **child** of the `HeroListComponent`.
<figure>
<img src="/resources/images/devguide/architecture/component-tree.png" alt="Metadata" align="left" style="width:300px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/architecture/component-tree.png" alt="Metadata" align="left" style="width:300px; margin-left:-40px;margin-right:10px"> </img>
</figure>
Notice how `<hero-detail>` rests comfortably among native HTML elements. Custom components mix seamlessly with native HTML in the same layouts.
@ -122,7 +122,7 @@ Notice how `<hero-detail>` rests comfortably among native HTML elements. Custom
## Metadata
<figure>
<img src="/resources/images/devguide/architecture/metadata.png" alt="Metadata" align="left" style="width:150px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/architecture/metadata.png" alt="Metadata" align="left" style="width:150px; margin-left:-40px;margin-right:10px"> </img>
</figure>
<p style="padding-top:10px">Metadata tells Angular how to process a class.</p>
@ -150,7 +150,7 @@ This is one way to tell Angular that the component's constructor requires a `Her
so it can get the list of heroes to display.
<figure>
<img src="/resources/images/devguide/architecture/template-metadata-component.png" alt="Metadata" align="left" style="height:200px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/architecture/template-metadata-component.png" alt="Metadata" align="left" style="height:200px; margin-left:-40px;margin-right:10px"> </img>
</figure>
The metadata in the `@Component` tells Angular where to get the major building blocks you specify for the component.
@ -171,7 +171,7 @@ Without a framework, you would be responsible for pushing data values into the H
into actions and value updates. Writing such push/pull logic by hand is tedious, error-prone, and a nightmare to
read as any experienced jQuery programmer can attest.
<figure>
<img src="/resources/images/devguide/architecture/databinding.png" alt="Data Binding" style="width:220px; float:left; margin-left:-40px;margin-right:20px"> </img>
<img src="assets/images/devguide/architecture/databinding.png" alt="Data Binding" style="width:220px; float:left; margin-left:-40px;margin-right:20px"> </img>
</figure>
Angular supports **data binding**,
@ -198,13 +198,13 @@ Angular processes *all* data bindings once per JavaScript event cycle,
from the root of the application component tree through all child components.
<figure>
<img src="/resources/images/devguide/architecture/component-databinding.png" alt="Data Binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/architecture/component-databinding.png" alt="Data Binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px"> </img>
</figure>
Data binding plays an important role in communication
between a template and its component.<br class="l-clear-both">
<figure>
<img src="/resources/images/devguide/architecture/parent-child-binding.png" alt="Parent/Child binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/architecture/parent-child-binding.png" alt="Parent/Child binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px"> </img>
</figure>
Data binding is also important for communication between parent and child components.<br class="l-clear-both">
@ -215,7 +215,7 @@ Data binding is also important for communication between parent and child compon
## Directives
<figure>
<img src="/resources/images/devguide/architecture/directive.png" alt="Parent child" style="float:left; width:150px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/architecture/directive.png" alt="Parent child" style="float:left; width:150px; margin-left:-40px;margin-right:10px"> </img>
</figure>
Angular templates are *dynamic*. When Angular renders them, it transforms the DOM
@ -260,7 +260,7 @@ Of course, you can also write your own directives. Components such as
## Services
<figure>
<img src="/resources/images/devguide/architecture/service.png" alt="Service" style="float:left; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/architecture/service.png" alt="Service" style="float:left; margin-left:-40px;margin-right:10px"> </img>
</figure>
_Service_ is a broad category encompassing any value, function, or feature that your application needs.
@ -305,7 +305,7 @@ application logic into services and make those services available to components
## Dependency injection
<figure>
<img src="/resources/images/devguide/architecture/dependency-injection.png" alt="Service" style="float:left; width:200px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/architecture/dependency-injection.png" alt="Service" style="float:left; width:200px; margin-left:-40px;margin-right:10px"> </img>
</figure>
_Dependency injection_ is a way to supply a new instance of a class
@ -324,7 +324,7 @@ This is *dependency injection*.
The process of `HeroService` injection looks a bit like this:
<figure>
<img src="/resources/images/devguide/architecture/injector-injects.png" alt="Service"> </img>
<img src="assets/images/devguide/architecture/injector-injects.png" alt="Service"> </img>
</figure>
If the injector doesn't have a `HeroService`, how does it know how to make one?

View File

@ -117,7 +117,7 @@ recognizes the directive when it encounters `myHighlight` in the template.
Now when the app runs, the `myHighlight` directive highlights the paragraph text.
<figure class='image-display'>
<img src="/resources/images/devguide/attribute-directives/first-highlight.png" alt="First Highlight"> </img>
<img src="assets/images/devguide/attribute-directives/first-highlight.png" alt="First Highlight"> </img>
</figure>
@ -180,7 +180,7 @@ Here's the updated directive in full:
Run the app and confirm that the background color appears when the mouse hovers over the `p` and
disappears as it moves out.
<figure class='image-display'>
<img src="/resources/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>
@ -260,7 +260,7 @@ lets you pick the highlight color with a radio button and bind your color choice
Update `app.component.html` as follows:
Revise the `AppComponent.color` so that it has no initial value.Here is the harness and directive in action.
<figure class='image-display'>
<img src="/resources/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>
@ -292,7 +292,7 @@ because you made it _public_ with the `@Input` !{_decorator}.
Here's how the harness should work when you're done coding.
<figure class='image-display'>
<img src="/resources/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>

View File

@ -8,6 +8,10 @@ An annotated history of recent documentation improvements.
The Angular documentation is a living document with continuous improvements.
This log calls attention to recent significant changes.
## NEW: Downloadable examples for each guide (2017-02-28)
Now you can download the sample code for any guide and run it locally.
Look for the new download links next to the "live example" links.
## Template Syntax/Structural Directives: refreshed (2017-02-06)
The [_Template-Syntax_](template-syntax.html) and [_Structural Directives_](structural-directives.html)
guides were significantly revised for clarity, accuracy, and current recommended practices.

View File

@ -5,100 +5,96 @@ Component Styles
Learn how to apply CSS styles to components.
@description
Angular applications are styled with regular CSS. That means we can apply
everything we know about CSS stylesheets, selectors, rules, and media queries
to our Angular applications directly.
Angular applications are styled with standard CSS. That means you can apply
everything you know about CSS stylesheets, selectors, rules, and media queries
directly to Angular applications.
On top of this, Angular has the ability to bundle *component styles*
with our components enabling a more modular design than regular stylesheets.
Additionally, Angular can bundle *component styles*
with components, enabling a more modular design than regular stylesheets.
In this chapter we learn how to load and apply these *component styles*.
This page describes how to load and apply these component styles.
## Table Of Contents
* [Using Component Styles](#using-component-styles)
* [Using component styles](#using-component-styles)
* [Special selectors](#special-selectors)
* [Loading Styles into Components](#loading-styles)
* [Controlling View Encapsulation: Emulated, Native, and None](#view-encapsulation)
* [Appendix 1: Inspecting the generated runtime component styles](#inspect-generated-css)
* [Appendix 2: Loading Styles with Relative URLs](#relative-urls)
* [Loading styles into components](#loading-styles)
* [Controlling view encapsulation: native, emulated, and none](#view-encapsulation)
* [Appendix 1: Inspecting the CSS generated in emulated view encapsulation](#inspect-generated-css)
* [Appendix 2: Loading styles with relative URLs](#relative-urls)
Run the <live-example></live-example> of the code shown in this chapter.
You can run the <live-example></live-example> in Plunker and download the code from there.
## Using Component Styles
## Using component styles
For every Angular component we write, we may define not only an HTML template,
For every Angular component you write, you may define not only an HTML template,
but also the CSS styles that go with that template,
specifying any selectors, rules, and media queries that we need.
specifying any selectors, rules, and media queries that you need.
One way to do this is to set the `styles` property in the component metadata.
The `styles` property takes #{_an} #{_array} of strings that contain CSS code.
Usually we give it one string as in this example:
Usually you give it one string, as in the following example:
{@example 'component-styles/ts/src/app/hero-app.component.ts'}
Component styles differ from traditional, global styles in a couple of ways.
Firstly, the selectors we put into a component's styles *only apply within the template
of that component*. The `h1` selector in the example above only applies to the `<h1>` tag
The selectors you put into a component's styles apply only within the template
of that component. The `h1` selector in the preceding example applies only to the `<h1>` tag
in the template of `HeroAppComponent`. Any `<h1>` elements elsewhere in
the application are unaffected.
This is a big improvement in modularity compared to how CSS traditionally works:
This is a big improvement in modularity compared to how CSS traditionally works.
1. We can use the CSS class names and selectors that make the most sense in the context of each component.
1. Class names and selectors are local to the component and won't collide with
classes and selectors used elsewhere in the application.
1. Our component's styles *cannot* be changed by changes to styles elsewhere in the application.
1. We can co-locate the CSS code of each component with the TypeScript and HTML code of the component,
which leads to a neat and tidy project structure.
1. We can change or remove component CSS code in the future without trawling through the
whole application to see where else it may have been used. We just look at the component we're in.
* You can use the CSS class names and selectors that make the most sense in the context of each component.
* Class names and selectors are local to the component and don't collide with
classes and selectors used elsewhere in the application.
* Changes to styles elsewhere in the application don't affect the component's styles.
* You can co-locate the CSS code of each component with the TypeScript and HTML code of the component,
which leads to a neat and tidy project structure.
* You can change or remove component CSS code without searching through the
whole application to find where else the code is used.
{@a special-selectors}
## Special selectors
Component styles have a few special *selectors* from the world of
[shadow DOM style scoping](https://www.w3.org/TR/css-scoping-1):
Component styles have a few special *selectors* from the world of shadow DOM style scoping
(described in the [CSS Scoping Module Level 1](https://www.w3.org/TR/css-scoping-1) page on the
[W3C](https://www.w3.org) site).
The following sections describe these selectors.
### :host
Use the `:host` pseudo-class selector to target styles in the element that *hosts* the component (as opposed to
targeting elements *inside* the component's template):
targeting elements *inside* the component's template).
{@example 'component-styles/ts/src/app/hero-details.component.css' region='host'}
This is the *only* way we can target the host element. We cannot reach
it from inside the component with other selectors, because it is not part of the
component's own template. It is in a parent component's template.
The `:host` selector is the only way to target the host element. You can't reach
the host element from inside the component with other selectors because it's not part of the
component's own template. The host element is in a parent component's template.
Use the *function form* to apply host styles conditionally by
including another selector inside parentheses after `:host`.
In the next example we target the host element again, but only when it also has the `active` CSS class.
The next example targets the host element again, but only when it also has the `active` CSS class.
{@example 'component-styles/ts/src/app/hero-details.component.css' region='hostfunction'}
### :host-context
Sometimes it is useful to apply styles based on some condition *outside* a component's view.
For example, there may be a CSS theme class applied to the document `<body>` element, and
we want to change how our component looks based on that.
Sometimes it's useful to apply styles based on some condition *outside* of a component's view.
For example, a CSS theme class could be applied to the document `<body>` element, and
you want to change how your component looks based on that.
Use the `:host-context()` pseudo-class selector. It works just like the function
form of `:host()`. It looks for a CSS class in *any ancestor* of the component host element, all the way
up to the document root. It's useful when combined with another selector.
Use the `:host-context()` pseudo-class selector, which works just like the function
form of `:host()`. The `:host-context()` selector looks for a CSS class in any ancestor of the component host element,
up to the document root. The `:host-context()` selector is useful when combined with another selector.
In the following example, we apply a `background-color` style to all `<h2>` elements *inside* the component, only
The following example applies a `background-color` style to all `<h2>` elements *inside* the component, only
if some ancestor element has the CSS class `theme-light`.
@ -108,24 +104,23 @@ if some ancestor element has the CSS class `theme-light`.
Component styles normally apply only to the HTML in the component's own template.
We can use the `/deep/` selector to force a style down through the child component tree into all the child component views.
The `/deep/` selector works to any depth of nested components, and it applies *both to the view
children and the content children* of the component.
Use the `/deep/` selector to force a style down through the child component tree into all the child component views.
The `/deep/` selector works to any depth of nested components, and it applies to both the view
children and content children of the component.
In this example, we target all `<h3>` elements, from the host element down
through this component to all of its child elements in the DOM:
The following example targets all `<h3>` elements, from the host element down
through this component to all of its child elements in the DOM.
{@example 'component-styles/ts/src/app/hero-details.component.css' region='deep'}
The `/deep/` selector also has the alias `>>>`. We can use either of the two interchangeably.
The `/deep/` selector also has the alias `>>>`. You can use either interchangeably.
~~~ {.alert.is-important}
The `/deep/` and `>>>` selectors should only be used with **emulated** view encapsulation.
This is the default and it is what we use most of the time. See the
[Controlling View Encapsulation](#view-encapsulation)
section for more details.
Use the `/deep/` and `>>>` selectors only with *emulated* view encapsulation.
Emulated is the default and most commonly used view encapsulation. For more information, see the
[Controlling view encapsulation](#view-encapsulation) section.
~~~
@ -134,53 +129,54 @@ section for more details.
{@a loading-styles}
## Loading Styles into Components
## Loading styles into components
We have several ways to add styles to a component:
* inline in the template HTML
* by setting `styles` or `styleUrls` metadata
* with CSS imports
There are several ways to add styles to a component:
* By setting `styles` or `styleUrls` metadata.
* Inline in the template HTML.
* With CSS imports.
The scoping rules outlined above apply to each of these loading patterns.
The scoping rules outlined earlier apply to each of these loading patterns.
### Styles in Metadata
### Styles in metadata
We can add a `styles` #{_array} property to the `@Component` #{_decorator}.
You can add a `styles` #{_array} property to the `@Component` #{_decorator}.
Each string in the #{_array} (usually just one string) defines the CSS.
{@example 'component-styles/ts/src/app/hero-app.component.ts'}
### Template Inline Styles
### Style URLs in metadata
We can embed styles directly into the HTML template by putting them
inside `<style>` tags.
{@example 'component-styles/ts/src/app/hero-controls.component.ts' region='inlinestyles'}
### Style URLs in Metadata
We can load styles from external CSS files by adding a `styleUrls` attribute
You can load styles from external CSS files by adding a `styleUrls` attribute
into a component's `@Component` #{_decorator}:
{@example 'component-styles/ts/src/app/hero-details.component.ts' region='styleurls'}
### Template Link Tags
### Template inline styles
We can also embed `<link>` tags into the component's HTML template.
You can embed styles directly into the HTML template by putting them
inside `<style>` tags.
{@example 'component-styles/ts/src/app/hero-controls.component.ts' region='inlinestyles'}
### Template link tags
You can also embed `<link>` tags into the component's HTML template.
As with `styleUrls`, the link tag's `href` URL is relative to the
application root, not relative to the component file.
application root, not the component file.
{@example 'component-styles/ts/src/app/hero-team.component.ts' region='stylelink'}
### CSS @imports
We can also import CSS files into our CSS files by using the standard CSS
[`@import` rule](https://developer.mozilla.org/en/docs/Web/CSS/@import).
You can also import CSS files into the CSS files using the standard CSS `@import` rule.
For details, see [`@import`](https://developer.mozilla.org/en/docs/Web/CSS/@import)
on the [MDN](https://developer.mozilla.org) site.
{@example 'component-styles/ts/src/app/hero-details.component.css' region='import'}
@ -189,48 +185,49 @@ We can also import CSS files into our CSS files by using the standard CSS
{@a view-encapsulation}
## Controlling View Encapsulation: Native, Emulated, and None
## Controlling view encapsulation: native, emulated, and none
As discussed above, component CSS styles are *encapsulated* into the component's own view and do
not affect the rest of the application.
As discussed earlier, component CSS styles are encapsulated into the component's view and don't
affect the rest of the application.
We can control how this encapsulation happens on a *per
component* basis by setting the *view encapsulation mode* in the component metadata. There
are three modes to choose from:
To control how this encapsulation happens on a *per
component* basis, you can set the *view encapsulation mode* in the component metadata.
Choose from the following modes:
* `Native` view encapsulation uses the browser's native [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
implementation to attach a Shadow DOM to the component's host element, and then puts the component
view inside that Shadow DOM. The component's styles are included within the Shadow DOM.
* `Emulated` view encapsulation (**the default**) emulates the behavior of Shadow DOM by preprocessing
* `Native` view encapsulation uses the browser's native shadow DOM implementation (see
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
on the [MDN](https://developer.mozilla.org) site)
to attach a shadow DOM to the component's host element, and then puts the component
view inside that shadow DOM. The component's styles are included within the shadow DOM.
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
(and renaming) the CSS code to effectively scope the CSS to the component's view.
See [Appendix 1](#inspect-generated-css) for details.
For details, see [Appendix 1](#inspect-generated-css).
* `None` means that Angular does no view encapsulation.
Angular adds the CSS to the global styles.
The scoping rules, isolations, and protections discussed earlier do not apply.
The scoping rules, isolations, and protections discussed earlier don't apply.
This is essentially the same as pasting the component's styles into the HTML.
Set the components encapsulation mode using the `encapsulation` property in the component metadata:
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
{@example 'component-styles/ts/src/app/quest-summary.component.ts' region='encapsulation.native'}
`Native` view encapsulation only works on [browsers that have native support
for Shadow DOM](http://caniuse.com/#feat=shadowdom). The support is still limited,
`Native` view encapsulation only works on browsers that have native support
for shadow DOM (see [Shadow DOM v0](http://caniuse.com/#feat=shadowdom) on the
[Can I use](http://caniuse.com) site). The support is still limited,
which is why `Emulated` view encapsulation is the default mode and recommended
in most cases.
{@a inspect-generated-css}
## Appendix 1: Inspecting The CSS Generated in Emulated View Encapsulation
## Appendix 1: Inspecting the CSS generated in emulated view encapsulation
When using the default emulated view encapsulation, Angular preprocesses
all component styles so that they approximate the standard Shadow CSS scoping rules.
When using emulated view encapsulation, Angular preprocesses
all component styles so that they approximate the standard shadow CSS scoping rules.
When we inspect the DOM of a running Angular application with emulated view
encapsulation enabled, we see that each DOM element has some extra attributes
In the DOM of a running Angular application with emulated view
encapsulation enabled, each DOM element has some extra attributes
attached to it:
<code-example format="">
@ -243,16 +240,15 @@ attached to it:
</code-example>
We see two kinds of generated attributes:
* An element that would be a Shadow DOM host in native encapsulation has a
There are two kinds of generated attributes:
* An element that would be a shadow DOM host in native encapsulation has a
generated `_nghost` attribute. This is typically the case for component host elements.
* An element within a component's view has a `_ngcontent` attribute
that identifies to which host's emulated Shadow DOM this element belongs.
that identifies to which host's emulated shadow DOM this element belongs.
The exact values of these attributes are not important. They are automatically
generated and we never refer to them in application code. But they are targeted
by the generated component styles, which we'll find in the `<head>` section of the DOM:
The exact values of these attributes aren't important. They are automatically
generated and you never refer to them in application code. But they are targeted
by the generated component styles, which are in the `<head>` section of the DOM:
<code-example format="">
[_nghost-pmm-5] {
@ -267,16 +263,14 @@ by the generated component styles, which we'll find in the `<head>` section of t
</code-example>
These are the styles we wrote, post-processed so that each selector is augmented
These styles are post-processed so that each selector is augmented
with `_nghost` or `_ngcontent` attribute selectors.
These extra selectors enable the scoping rules described in this guide.
We'll likely live with *emulated* mode until shadow DOM gains traction.
These extra selectors enable the scoping rules described in this page.
{@a relative-urls}
## Appendix 2: Loading Styles with Relative URLs
## Appendix 2: Loading styles with relative URLs
It's common practice to split a component's code, HTML, and CSS into three separate files in the same directory:
<code-example format="nocode">
@ -286,6 +280,6 @@ It's common practice to split a component's code, HTML, and CSS into three separ
</code-example>
We include the template and CSS files by setting the `templateUrl` and `styleUrls` metadata properties respectively.
You include the template and CSS files by setting the `templateUrl` and `styleUrls` metadata properties respectively.
Because these files are co-located with the component,
it would be nice to refer to them by name without also having to specify a path back to the root of the application.

View File

@ -342,7 +342,7 @@ See also the [*APP_BASE_HREF*](../api/common/index/APP_BASE_HREF-let.html "API:
That's the root folder and you'd add `<base href="/">` near the top of `index.html` because `/` is the root of the app.
But on the shared or production server, you might serve the app from a subfolder.
For example, when the URL to load the app is something like `http://www.mysite.com/mysrc/app/`,
For example, when the URL to load the app is something like `http://www.mysite.com/my/app/`,
the subfolder is `my/app/` and you should add `<base href="/my/app/">` to the server version of the `index.html`.
When the `base` tag is misconfigured, the app fails to load and the browser console displays `404 - Not Found` errors

View File

@ -14,7 +14,7 @@ conditionally show a message below the list.
The final UI looks like this:
<figure class='image-display'>
<img src="/resources/images/devguide/displaying-data/final.png" alt="Final UI"> </img>
<img src="assets/images/devguide/displaying-data/final.png" alt="Final UI"> </img>
</figure>
# Contents
@ -63,7 +63,7 @@ inside the `<my-app>` tag.
Now run the app. It should display the title and hero name:
<figure class='image-display'>
<img src="/resources/images/devguide/displaying-data/title-and-hero.png" alt="Title and Hero"> </img>
<img src="assets/images/devguide/displaying-data/title-and-hero.png" alt="Title and Hero"> </img>
</figure>
## Template inline or template file?
@ -111,7 +111,7 @@ In this case, `ngFor` is displaying !{_an} !{_array}, but `ngFor` can
repeat items for any [iterable](!{_iterableUrl}) object.Now the heroes appear in an unordered list.
<figure class='image-display'>
<img src="/resources/images/devguide/displaying-data/hero-names-list.png" alt="After ngfor"> </img>
<img src="assets/images/devguide/displaying-data/hero-names-list.png" alt="After ngfor"> </img>
</figure>

View File

@ -5,74 +5,73 @@ Forms
A form creates a cohesive, effective, and compelling data entry experience. An Angular form coordinates a set of data-bound user controls, tracks changes, validates input, and presents errors.
@description
Weve all used a form to log in, submit a help request, place an order, book a flight,
schedule a meeting, and perform countless other data entry tasks.
Forms are the mainstay of business applications.
You use forms to log in, submit a help request, place an order, book a flight,
schedule a meeting, and perform countless other data-entry tasks.
Any seasoned web developer can slap together an HTML form with all the right tags.
It's more challenging to create a cohesive data entry experience that guides the
user efficiently and effectively through the workflow behind the form.
In developing a form, it's important to create a data-entry experience that guides the
user efficiently and effectively through the workflow.
*That* takes design skills that are, to be frank, well out of scope for this guide.
Developing forms requires design skills (which are out of scope for this page), as well as framework support for
*two-way data binding, change tracking, validation, and error handling*,
which you'll learn about on this page.
It also takes framework support for
**two-way data binding, change tracking, validation, and error handling**
... which we shall cover in this guide on Angular forms.
This page shows you how to build a simple form from scratch. Along the way you'll learn how to:
We will build a simple form from scratch, one step at a time. Along the way we'll learn how to:
- Build an Angular form with a component and template.
- Use `ngModel` to create two-way data bindings for reading and writing input-control values.
- Track state changes and the validity of form controls.
- Provide visual feedback using special CSS classes that track the state of the controls.
- Display validation errors to users and enable/disable form controls.
- Share information across HTML elements using template reference variables.
- Build an Angular form with a component and template
- Use `ngModel` to create two-way data bindings for reading and writing input control values
- Track state changes and the validity of form controls
- Provide visual feedback using special CSS classes that track the state of the controls
- Display validation errors to users and enable/disable form controls
- Share information across HTML elements using template reference variables
Run the <live-example></live-example>.
You can run the <live-example></live-example> in Plunker and download the code from there.
## Template-driven forms
Many of us will build forms by writing templates in the Angular [template syntax](./template-syntax.html) with
the form-specific directives and techniques described in this guide.
You can build forms by writing templates in the Angular [template syntax](./template-syntax.html) with
the form-specific directives and techniques described in this page.
That's not the only way to create a form but it's the way we'll cover in this guide.We can build almost any form we need with an Angular template &mdash; login forms, contact forms, pretty much any business form.
We can lay out the controls creatively, bind them to data, specify validation rules and display validation errors,
You can also use a reactive (or model-driven) approach to build forms.
However, this page focuses on template-driven forms.
You can build almost any form with an Angular template&mdash;login forms, contact forms, and pretty much any business form.
You can lay out the controls creatively, bind them to data, specify validation rules and display validation errors,
conditionally enable or disable specific controls, trigger built-in visual feedback, and much more.
It will be pretty easy because Angular handles many of the repetitive, boilerplate tasks we'd
otherwise wrestle with ourselves.
Angular makes the process easy by handling many of the repetitive, boilerplate tasks you'd
otherwise wrestle with yourself.
We'll discuss and learn to build a template-driven form that looks like this:
You'll learn to build a template-driven form that looks like this:
<figure class='image-display'>
<img src="/resources/images/devguide/forms/hero-form-1.png" width="400px" alt="Clean Form"> </img>
<img src="assets/images/devguide/forms/hero-form-1.png" width="400px" alt="Clean Form"> </img>
</figure>
Here at the *Hero Employment Agency* we use this form to maintain personal information about heroes.
Every hero needs a job. It's our company mission to match the right hero with the right crisis!
The *Hero Employment Agency* uses this form to maintain personal information about heroes.
Every hero needs a job. It's the company mission to match the right hero with the right crisis.
Two of the three fields on this form are required. Required fields have a green bar on the left to make them easy to spot.
If we delete the hero name, the form displays a validation error in an attention-grabbing style:
If you delete the hero name, the form displays a validation error in an attention-grabbing style:
<figure class='image-display'>
<img src="/resources/images/devguide/forms/hero-form-2.png" width="400px" alt="Invalid, Name Required"> </img>
<img src="assets/images/devguide/forms/hero-form-2.png" width="400px" alt="Invalid, Name Required"> </img>
</figure>
Note that the submit button is disabled, and the "required" bar to the left of the input control changed from green to red.
Note that the *Submit* button is disabled, and the "required" bar to the left of the input control changes from green to red.
We'll customize the colors and location of the "required" bar with standard CSS.
We'll build this form in small steps:
You can customize the colors and location of the "required" bar with standard CSS.
You'll build this form in small steps:
1. Create the `Hero` model class.
1. Create the component that controls the form.
1. Create a template with the initial form layout.
1. Bind data properties to each form control using the `ngModel` two-way data binding syntax.
1. Add a `name` attribute to each form input control.
1. Bind data properties to each form control using the `ngModel` two-way data-binding syntax.
1. Add a `name` attribute to each form-input control.
1. Add custom CSS to provide visual feedback.
1. Show and hide validation error messages.
1. Handle form submission with **ngSubmit**.
1. Disable the forms submit button until the form is valid.
1. Show and hide validation-error messages.
1. Handle form submission with *ngSubmit*.
1. Disable the forms *Submit* button until the form is valid.
## Setup
Follow the [setup](setup.html) instructions for creating a new project
@ -80,11 +79,11 @@ named <span ngio-ex>angular-forms</span>.
## Create the Hero model class
As users enter form data, we'll capture their changes and update an instance of a model.
We can't lay out the form until we know what the model looks like.
As users enter form data, you'll capture their changes and update an instance of a model.
You can't lay out the form until you know what the model looks like.
A model can be as simple as a "property bag" that holds facts about a thing of application importance.
That describes well our `Hero` class with its three required fields (`id`, `name`, `power`)
That describes well the `Hero` class with its three required fields (`id`, `name`, `power`)
and one optional field (`alterEgo`).
In the `!{_appDir}` directory, create the following file with the given content:
@ -92,60 +91,60 @@ In the `!{_appDir}` directory, create the following file with the given content:
{@example 'forms/ts/src/app/hero.ts'}
It's an anemic model with few requirements and no behavior. Perfect for our demo.
It's an anemic model with few requirements and no behavior. Perfect for the demo.
The TypeScript compiler generates a public field for each `public` constructor parameter and
assigns the parameters value to that field automatically when we create new heroes.
automatically assigns the parameters value to that field when you create heroes.
The `alterEgo` is optional, so the constructor lets us omit it; note the (?) in `alterEgo?`.
The `alterEgo` is optional, so the constructor lets you omit it; note the question mark (?) in `alterEgo?`.
We can create a new hero like this:
You can create a new hero like this:
## Create a form component
An Angular form has two parts: an HTML-based _template_ and a component _class_
to handle data and user interactions programmatically.
We begin with the class because it states, in brief, what the hero editor can do.
Begin with the class because it states, in brief, what the hero editor can do.
Create the following file with the given content:
Theres nothing special about this component, nothing form-specific,
nothing to distinguish it from any component we've written before.
nothing to distinguish it from any component you've written before.
Understanding this component requires only the Angular concepts covered in previous guides.
Understanding this component requires only the Angular concepts covered in previous pages.
1. The code imports the Angular core library, and the `Hero` model we just created.
1. The `@Component` selector value of "hero-form" means we can drop this form in a parent template with a `<hero-form>` tag.
1. The `moduleId: module.id` property sets the base for module-relative loading of the `templateUrl`.
1. The `templateUrl` property points to a separate file for the template HTML.
1. We defined dummy data for `model` and `powers`, as befits a demo.
Down the road, we can inject a data service to get and save real data
or perhaps expose these properties as
[inputs and outputs](./template-syntax.html#inputs-outputs) for binding to a
parent component. None of this concerns us now and these future changes won't affect our form.
1. We threw in a `diagnostic` property to return a JSON representation of our model.
It'll help us see what we're doing during our development; we've left ourselves a cleanup note to discard it later.
- The code imports the Angular core library and the `Hero` model you just created.
- The `@Component` selector value of "hero-form" means you can drop this form in a parent template with a `<hero-form>` tag.
- The `moduleId: module.id` property sets the base for module-relative loading of the `templateUrl`.
- The `templateUrl` property points to a separate file for the template HTML.
- You defined dummy data for `model` and `powers`, as befits a demo.
Down the road, you can inject a data service to get and save real data
or perhaps expose these properties as inputs and outputs
(see [Input and output properties](./template-syntax.html#inputs-outputs) on the
[Template Syntax](./template-syntax.html) page) for binding to a
parent component. This is not a concern now and these future changes won't affect the form.
- You added a `diagnostic` property to return a JSON representation of the model.
It'll help you see what you're doing during development; you've left yourself a cleanup note to discard it later.
### Why the separate template file?
Why don't we write the template inline in the component file as we often do elsewhere?
Why don't you write the template inline in the component file as you often do elsewhere?
There is no “right” answer for all occasions. We like inline templates when they are short.
Most form templates won't be short. TypeScript and JavaScript files generally aren't the best place to
write (or read) large stretches of HTML and few editors are much help with files that have a mix of HTML and code.
We also like short files with a clear and obvious purpose like this one.
There is no "right" answer for all occasions. Inline templates are useful when they are short.
Most form templates aren't short. TypeScript and JavaScript files generally aren't the best place to
write (or read) large stretches of HTML, and few editors help with files that have a mix of HTML and code.
Form templates tend to be quite large even when displaying a small number of fields
Form templates tend to be large, even when displaying a small number of fields,
so it's usually best to put the HTML template in a separate file.
We'll write that template file in a moment. Before we do, we'll take a step back
and revise the `app.module.ts` and `app.component.ts` to make use of the new `HeroFormComponent`.
You'll write that template file in a moment. First,
revise the `app.module.ts` and `app.component.ts` to make use of the new `HeroFormComponent`.
## Revise *app.module.ts*
`app.module.ts` defines the application's root module. In it we identify the external modules we'll use in our application
and declare the components that belong to this module, such as our `HeroFormComponent`.
`app.module.ts` defines the application's root module. In it you identify the external modules you'll use in the application
and declare the components that belong to this module, such as the `HeroFormComponent`.
Because template-driven forms are in their own module, we need to add the `FormsModule` to the array of
`imports` for our application module before we can use forms.
Because template-driven forms are in their own module, you need to add the `FormsModule` to the array of
`imports` for the application module before you can use forms.
Replace the contents of the "QuickStart" version with the following:
@ -154,19 +153,19 @@ Replace the contents of the "QuickStart" version with the following:
There are three changes:
1. We import `FormsModule` and our new `HeroFormComponent`.
1. You import `FormsModule` and the new `HeroFormComponent`.
1. We add the `FormsModule` to the list of `imports` defined in the `ngModule` decorator. This gives our application
1. You add the `FormsModule` to the list of `imports` defined in the `ngModule` decorator. This gives the application
access to all of the template-driven forms features, including `ngModel`.
1. We add the `HeroFormComponent` to the list of `declarations` defined in the `ngModule` decorator. This makes
1. You add the `HeroFormComponent` to the list of `declarations` defined in the `ngModule` decorator. This makes
the `HeroFormComponent` component visible throughout this module.
~~~ {.alert.is-important}
If a component, directive, or pipe belongs to a module in the `imports` array, _DON'T_ re-declare it in the `declarations` array.
If you wrote it and it should belong to this module, _DO_ declare it in the `declarations` array.
If a component, directive, or pipe belongs to a module in the `imports` array, _don't_ re-declare it in the `declarations` array.
If you wrote it and it should belong to this module, _do_ declare it in the `declarations` array.
~~~
@ -174,7 +173,7 @@ If you wrote it and it should belong to this module, _DO_ declare it in th
## Revise *app.component.ts*
`AppComponent` is the application's root component. It will host our new `HeroFormComponent`.
`AppComponent` is the application's root component. It will host the new `HeroFormComponent`.
Replace the contents of the "QuickStart" version with the following:
@ -184,140 +183,139 @@ Replace the contents of the "QuickStart" version with the following:
There are only two changes.
The `template` is simply the new element tag identified by the component's `selector` property.
This will display the hero form when the application component is loaded.
We've also dropped the `name` field from the class body.
This displays the hero form when the application component is loaded.
You've also dropped the `name` field from the class body.
## Create an initial HTML form template
Create the new template file with the following contents:
Create the template file with the following contents:
{@example 'forms/ts/src/app/hero-form.component.html' region='start'}
That is plain old HTML 5. We're presenting two of the `Hero` fields, `name` and `alterEgo`, and
The language is simply HTML5. You're presenting two of the `Hero` fields, `name` and `alterEgo`, and
opening them up for user input in input boxes.
The *Name* `<input>` control has the HTML5 `required` attribute;
the *Alter Ego* `<input>` control does not because `alterEgo` is optional.
We've got a *Submit* button at the bottom with some classes on it for styling.
You added a *Submit* button at the bottom with some classes on it for styling.
**We are not using Angular yet**. There are no bindings, no extra directives, just layout.
*You're not using Angular yet*. There are no bindings or extra directives, just layout.
The `container`, `form-group`, `form-control`, and `btn` classes
come from [Twitter Bootstrap](http://getbootstrap.com/css/). Purely cosmetic.
We're using Bootstrap to give the form a little style!
come from [Twitter Bootstrap](http://getbootstrap.com/css/). These classes are purely cosmetic.
Bootstrap gives the form a little style.
~~~ {.callout.is-important}
<header>
Angular forms do not require a style library
Angular forms don't require a style library
</header>
Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or
the styles of any external library. Angular apps can use any CSS library, or none at all.
the styles of any external library. Angular apps can use any CSS library or none at all.
~~~
Let's add the stylesheet. Open `index.html` and add the following link to the `<head>`:
To add the stylesheet, open `index.html` and add the following link to the `<head>`:
## Add powers with _*ngFor_
Our hero must choose one super power from a fixed list of Agency-approved powers.
We maintain that list internally (in `HeroFormComponent`).
The hero must choose one superpower from a fixed list of agency-approved powers.
You maintain that list internally (in `HeroFormComponent`).
We'll add a `select` to our
You'll add a `select` to the
form and bind the options to the `powers` list using `ngFor`,
a technique seen previously in the [Displaying Data](./displaying-data.html) guide.
a technique seen previously in the [Displaying Data](./displaying-data.html) page.
Add the following HTML *immediately below* the *Alter Ego* group:
This code repeats the `<option>` tag for each power in the list of powers.
The `pow` template input variable is a different power in each iteration;
we display its name using the interpolation syntax.
you display its name using the interpolation syntax.
## Two-way data binding with _ngModel_
Running the app right now would be disappointing.
<figure class='image-display'>
<img src="/resources/images/devguide/forms/hero-form-3.png" width="400px" alt="Early form with no binding"> </img>
<img src="assets/images/devguide/forms/hero-form-3.png" width="400px" alt="Early form with no binding"> </img>
</figure>
We don't see hero data because we are not binding to the `Hero` yet.
We know how to do that from earlier guides.
[Displaying Data](./displaying-data.html) taught us property binding.
[User Input](./user-input.html) showed us how to listen for DOM events with an
You don't see hero data because you're not binding to the `Hero` yet.
You know how to do that from earlier pages.
[Displaying Data](./displaying-data.html) teaches property binding.
[User Input](./user-input.html) shows how to listen for DOM events with an
event binding and how to update a component property with the displayed value.
Now we need to display, listen, and extract at the same time.
Now you need to display, listen, and extract at the same time.
We could use the techniques we already know, but
instead we'll introduce something new: the `[(ngModel)]` syntax, which
makes binding the form to the model super easy.
You could use the techniques you already know, but
instead you'll use the new `[(ngModel)]` syntax, which
makes binding the form to the model easy.
Find the `<input>` tag for *Name* and update it like this:
We added a diagnostic interpolation after the input tag
so we can see what we're doing.
We left ourselves a note to throw it away when we're done.
You added a diagnostic interpolation after the input tag
so you can see what you're doing.
You left yourself a note to throw it away when you're done.
Focus on the binding syntax: `[(ngModel)]="..."`.
If we run the app right now and started typing in the *Name* input box,
adding and deleting characters, we'd see them appearing and disappearing
If you ran the app now and started typing in the *Name* input box,
adding and deleting characters, you'd see them appear and disappear
from the interpolated text.
At some point it might look like this.
At some point it might look like this:
<figure class='image-display'>
<img src="/resources/images/devguide/forms/ng-model-in-action.png" width="400px" alt="ngModel in action"> </img>
<img src="assets/images/devguide/forms/ng-model-in-action.png" width="400px" alt="ngModel in action"> </img>
</figure>
The diagnostic is evidence that values really are flowing from the input box to the model and
back again.
That's **two-way data binding**!
For more information about `[(ngModel)]` and two-way data bindings, see
the [Template Syntax](template-syntax.html#ngModel) page.
Notice that we also added a `name` attribute to our `<input>` tag and set it to "name"
That's *two-way data binding*.
For more information, see
[Two-way binding with NgModel](template-syntax.html#ngModel) on the
the [Template Syntax](template-syntax.html) page.
Notice that you also added a `name` attribute to the `<input>` tag and set it to "name",
which makes sense for the hero's name. Any unique value will do, but using a descriptive name is helpful.
Defining a `name` attribute is a requirement when using `[(ngModel)]` in combination with a form.
Internally Angular creates `FormControl` instances and
Internally, Angular creates `FormControl` instances and
registers them with an `NgForm` directive that Angular attached to the `<form>` tag.
Each `FormControl` is registered under the name we assigned to the `name` attribute.
We'll talk about `NgForm` [later in this guide](#ngForm).
Let's add similar `[(ngModel)]` bindings and `name` attributes to *Alter Ego* and *Hero Power*.
We'll ditch the input box binding message
Each `FormControl` is registered under the name you assigned to the `name` attribute.
Read more in [The NgForm directive](#ngForm), later in this page.
Add similar `[(ngModel)]` bindings and `name` attributes to *Alter Ego* and *Hero Power*.
You'll ditch the input box binding message
and add a new binding (at the top) to the component's `diagnostic` property.
Then we can confirm that two-way data binding works *for the entire hero model*.
Then you can confirm that two-way data binding works *for the entire hero model*.
After revision, the core of our form should look like this:
After revision, the core of the form should look like this:
- Each input element has an `id` property that is used by the `label` element's `for` attribute
to match the label to its input control.
- Each input element has a `name` property that is required by Angular forms to register the control with the form.
If we run the app now and changed every hero model property, the form might display like this:
If you run the app now and change every hero model property, the form might display like this:
<figure class='image-display'>
<img src="/resources/images/devguide/forms/ng-model-in-action-2.png" width="400px" alt="ngModel in action"> </img>
<img src="assets/images/devguide/forms/ng-model-in-action-2.png" width="400px" alt="ngModel in action"> </img>
</figure>
The diagnostic near the top of the form
confirms that all of our changes are reflected in the model.
confirms that all of your changes are reflected in the model.
**Delete** the `{{diagnostic}}` binding at the top as it has served its purpose.
*Delete* the `{{diagnostic}}` binding at the top as it has served its purpose.
## Track control state and validity with _ngModel_
A form isn't just about data binding. We'd also like to know the state of the controls in our form.
Using `ngModel` in a form gives us more than just a two way data binding. It also tells
us if the user touched the control, if the value changed, or if the value became invalid.
Using `ngModel` in a form gives you more than just two-way data binding. It also tells
you if the user touched the control, if the value changed, or if the value became invalid.
The *NgModel* directive doesn't just track state; it updates the control with special Angular CSS classes that reflect the state.
We can leverage those class names to change the appearance of the control.
You can leverage those class names to change the appearance of the control.
<table>
@ -344,7 +342,7 @@ We can leverage those class names to change the appearance of the control.
<tr>
<td>
Control has been visited
The control has been visited.
</td>
@ -364,7 +362,7 @@ We can leverage those class names to change the appearance of the control.
<tr>
<td>
Control's value has changed
The control's value has changed.
</td>
@ -384,7 +382,7 @@ We can leverage those class names to change the appearance of the control.
<tr>
<td>
Control's value is valid
The control's value is valid.
</td>
@ -403,10 +401,10 @@ We can leverage those class names to change the appearance of the control.
</table>
Let's temporarily add a [template reference variable](./template-syntax.html#ref-vars) named `spy`
Temporarily add a [template reference variable](./template-syntax.html#ref-vars) named `spy`
to the _Name_ `<input>` tag and use it to display the input's CSS classes.
Now run the app, and look at the _Name_ input box.
Follow the next four steps *precisely*:
Now run the app and look at the _Name_ input box.
Follow these steps *precisely*:
1. Look but don't touch.
1. Click inside the name box, then click outside it.
@ -416,32 +414,32 @@ Follow the next four steps *precisely*:
The actions and effects are as follows:
<figure class='image-display'>
<img src="/resources/images/devguide/forms/control-state-transitions-anim.gif" alt="Control State Transition"> </img>
<img src="assets/images/devguide/forms/control-state-transitions-anim.gif" alt="Control State Transition"> </img>
</figure>
We should see the following transitions and class names:
You should see the following transitions and class names:
<figure class='image-display'>
<img src="/resources/images/devguide/forms/ng-control-class-changes.png" width="500px" alt="Control state transitions"> </img>
<img src="assets/images/devguide/forms/ng-control-class-changes.png" width="500px" alt="Control state transitions"> </img>
</figure>
The `ng-valid`/`ng-invalid` pair is the most interesting to us, because we want to send a
strong visual signal when the values are invalid. We also want to mark required fields.
To create such visual feedback, let's add definitions for the `ng-*` CSS classes.
The `ng-valid`/`ng-invalid` pair is the most interesting, because you want to send a
strong visual signal when the values are invalid. You also want to mark required fields.
To create such visual feedback, add definitions for the `ng-*` CSS classes.
**Delete** the `#spy` template reference variable and the `TODO` as they have served their purpose.
*Delete* the `#spy` template reference variable and the `TODO` as they have served their purpose.
## Add custom CSS for visual feedback
We can mark required fields and invalid data at the same time with a colored bar
You can mark required fields and invalid data at the same time with a colored bar
on the left of the input box:
<figure class='image-display'>
<img src="/resources/images/devguide/forms/validity-required-indicator.png" width="400px" alt="Invalid Form"> </img>
<img src="assets/images/devguide/forms/validity-required-indicator.png" width="400px" alt="Invalid Form"> </img>
</figure>
We achieve this effect by adding these class definitions to a new `forms.css` file
that we add to our project as a sibling to `index.html`:
You achieve this effect by adding these class definitions to a new `forms.css` file
that you add to the project as a sibling to `index.html`:
{@example 'forms/ts/src/forms.css'}
@ -449,52 +447,51 @@ that we add to our project as a sibling to `index.html`:
Update the `<head>` of `index.html` to include this style sheet:
## Show and hide validation error messages
We can do better. The _Name_ input box is required and clearing it turns the bar red.
That says *something* is wrong but we don't know *what* is wrong or what to do about it.
We can leverage the control's state to reveal a helpful message.
You can improve the form. The _Name_ input box is required and clearing it turns the bar red.
That says something is wrong but the user doesn't know *what* is wrong or what to do about it.
Leverage the control's state to reveal a helpful message.
Here's the way it should look when the user deletes the name:
When the user deletes the name, the form should look like this:
<figure class='image-display'>
<img src="/resources/images/devguide/forms/name-required-error.png" width="400px" alt="Name required"> </img>
<img src="assets/images/devguide/forms/name-required-error.png" width="400px" alt="Name required"> </img>
</figure>
To achieve this effect we extend the `<input>` tag with
1. a [template reference variable](./template-syntax.html#ref-vars)
1. the "*is required*" message in a nearby `<div>` which we'll display only if the control is invalid.
To achieve this effect, extend the `<input>` tag with the following:
- A [template reference variable](./template-syntax.html#ref-vars).
- The "*is required*" message in a nearby `<div>`, which you'll display only if the control is invalid.
Here's an example of adding an error message to the _name_ input box:
We need a template reference variable to access the input box's Angular control from within the template.
Here we created a variable called `name` and gave it the value "ngModel".
Here's an example of an error message added to the _name_ input box:
You need a template reference variable to access the input box's Angular control from within the template.
Here you created a variable called `name` and gave it the value "ngModel".
Why "ngModel"?
A directive's [exportAs](../api/core/index/Directive-decorator.html) property
tells Angular how to link the reference variable to the directive.
We set `name` to `ngModel` because the `ngModel` directive's `exportAs` property happens to be "ngModel".
We control visibility of the name error message by binding properties of the `name`
You set `name` to `ngModel` because the `ngModel` directive's `exportAs` property happens to be "ngModel".
You control visibility of the name error message by binding properties of the `name`
control to the message `<div>` element's `hidden` property.
In this example, we hide the message when the control is valid or pristine;
pristine means the user hasn't changed the value since it was displayed in this form.
In this example, you hide the message when the control is valid or pristine;
"pristine" means the user hasn't changed the value since it was displayed in this form.
This user experience is the developer's choice. Some folks want to see the message at all times.
If we ignore the `pristine` state, we would hide the message only when the value is valid.
If we arrive in this component with a new (blank) hero or an invalid hero,
we'll see the error message immediately, before we've done anything.
This user experience is the developer's choice. Some developers want the message to display at all times.
If you ignore the `pristine` state, you would hide the message only when the value is valid.
If you arrive in this component with a new (blank) hero or an invalid hero,
you'll see the error message immediately, before you've done anything.
Some folks find that behavior disconcerting.
They only want to see the message when the user makes an invalid change.
Some developers want to the message to display only when the user makes an invalid change.
Hiding the message while the control is "pristine" achieves that goal.
We'll see the significance of this choice when we [add a new hero](#new-hero) to the form.
You'll see the significance of this choice when you [add a new hero](#new-hero) to the form.
The hero *Alter Ego* is optional so we can leave that be.
The hero *Alter Ego* is optional so you can leave that be.
Hero *Power* selection is required.
We can add the same kind of error handling to the `<select>` if we want,
You can add the same kind of error handling to the `<select>` if you want,
but it's not imperative because the selection box already constrains the
power to valid values.
We'd like to add a new hero in this form.
We place a "New Hero" button at the bottom of the form and bind its click event to a `newHero` component method.
Now you'll add a new hero in this form.
Place a *New Hero* button at the bottom of the form and bind its click event to a `newHero` component method.
{@example 'forms/ts/src/app/hero-form.component.html' region='new-hero-button-no-reset'}
@ -506,66 +503,66 @@ We place a "New Hero" button at the bottom of the form and bind its click event
Run the application again, click the *New Hero* button, and the form clears.
The *required* bars to the left of the input box are red, indicating invalid `name` and `power` properties.
That's understandable as these are required fields.
The error messages are hidden because the form is pristine; we haven't changed anything yet.
The error messages are hidden because the form is pristine; you haven't changed anything yet.
Enter a name and click *New Hero* again.
The app displays a **_Name is required_** error message!
We don't want error messages when we create a new (empty) hero.
Why are we getting one now?
The app displays a _Name is required_ error message.
You don't want error messages when you create a new (empty) hero.
Why are you getting one now?
Inspecting the element in the browser tools reveals that the *name* input box is _no longer pristine_.
The form remembers that we entered a name before clicking *New Hero*.
The form remembers that you entered a name before clicking *New Hero*.
Replacing the hero object *did not restore the pristine state* of the form controls.
We have to clear all of the flags imperatively which we can do
You have to clear all of the flags imperatively, which you can do
by calling the form's `reset()` method after calling the `newHero()` method.
{@example 'forms/ts/src/app/hero-form.component.html' region='new-hero-button-form-reset'}
Now clicking "New Hero" both resets the form and its control flags.
Now clicking "New Hero" resets both the form and its control flags.
## Submit the form with _ngSubmit_
The user should be able to submit this form after filling it in.
The Submit button at the bottom of the form
The *Submit* button at the bottom of the form
does nothing on its own, but it will
trigger a form submit because of its type (`type="submit"`).
A "form submit" is useless at the moment.
To make it useful, bind the form's `ngSubmit` event property
to the hero form component's `onSubmit()` method:
We slipped in something extra there at the end! We defined a
template reference variable, **`#heroForm`**, and initialized it with the value "ngForm".
You added something extra at the end. You defined a
template reference variable, `#heroForm`, and initialized it with the value "ngForm".
The variable `heroForm` is now a reference to the `NgForm` directive that governs the form as a whole.
### The _NgForm_ directive
What `NgForm` directive?
We didn't add an [NgForm](../api/forms/index/NgForm-directive.html) directive!
You didn't add an [NgForm](../api/forms/index/NgForm-directive.html) directive.
Angular did. Angular creates and attaches an `NgForm` directive to the `<form>` tag automatically.
Angular did. Angular automatically creates and attaches an `NgForm` directive to the `<form>` tag.
The `NgForm` directive supplements the `form` element with additional features.
It holds the controls we created for the elements with an `ngModel` directive
and `name` attribute, and monitors their properties including their validity.
It holds the controls you created for the elements with an `ngModel` directive
and `name` attribute, and monitors their properties, including their validity.
It also has its own `valid` property which is true only *if every contained
control* is valid.
We'll bind the form's overall validity via
You'll bind the form's overall validity via
the `heroForm` variable to the button's `disabled` property
using an event binding. Here's the code:
If we run the application now, we find that the button is enabled
&mdash; although it doesn't do anything useful yet.
If you run the application now, you find that the button is enabled&mdash;although
it doesn't do anything useful yet.
Now if we delete the Name, we violate the "required" rule, which
Now if you delete the Name, you violate the "required" rule, which
is duly noted in the error message.
The Submit button is also disabled.
The *Submit* button is also disabled.
Not impressed? Think about it for a moment. What would we have to do to
Not impressed? Think about it for a moment. What would you have to do to
wire the button's enable/disabled state to the form's validity without Angular's help?
For us, it was as simple as:
For you, it was as simple as this:
1. Define a template reference variable on the (enhanced) form element.
2. Refer to that variable in a button many lines away.
@ -575,49 +572,47 @@ For us, it was as simple as:
Submitting the form isn't terribly dramatic at the moment.
An unsurprising observation for a demo. To be honest,
jazzing it up won't teach us anything new about forms.
But this is an opportunity to exercise some of our newly won
jazzing it up won't teach you anything new about forms.
But this is an opportunity to exercise some of your newly won
binding skills.
If you aren't interested, go ahead and skip to this guide's conclusion.
Let's do something more strikingly visual.
Let's hide the data entry area and display something else.
If you aren't interested, skip to this page's conclusion.
For a more strikingly visual effect,
hide the data entry area and display something else.
Start by wrapping the form in a `<div>` and bind
Wrap the form in a `<div>` and bind
its `hidden` property to the `HeroFormComponent.submitted` property.
The main form is visible from the start because the
`submitted` property is false until we submit the form,
`submitted` property is false until you submit the form,
as this fragment from the `HeroFormComponent` shows:
When we click the Submit button, the `submitted` flag becomes true and the form disappears
When you click the *Submit* button, the `submitted` flag becomes true and the form disappears
as planned.
Now the app needs to show something else while the form is in the submitted state.
Add the following HTML below the `<div>` wrapper we just wrote:
There's our hero again, displayed read-only with interpolation bindings.
Add the following HTML below the `<div>` wrapper you just wrote:
There's the hero again, displayed read-only with interpolation bindings.
This `<div>` appears only while the component is in the submitted state.
The HTML includes an _Edit_ button whose click event is bound to an expression
The HTML includes an *Edit* button whose click event is bound to an expression
that clears the `submitted` flag.
When we click the _Edit_ button, this block disappears and the editable form reappears.
That's as much drama as we can muster for now.
When you click the *Edit* button, this block disappears and the editable form reappears.
## Conclusion
The Angular form discussed in this guide takes advantage of the following
The Angular form discussed in this page takes advantage of the following
framework features to provide support for data modification, validation, and more:
- An Angular HTML form template.
- A form component class with a `@Component` decorator.
- Handling form submission by binding to the `NgForm.ngSubmit` event property.
- Template reference variables such as `#heroForm` and `#name`.
- Template-reference variables such as `#heroForm` and `#name`.
- `[(ngModel)]` syntax for two-way data binding.
- The use of `name` attributes for validation and form element change tracking.
- The use of `name` attributes for validation and form-element change tracking.
- The reference variables `valid` property on input controls to check if a control is valid and show/hide error messages.
- Controlling the submit button's enabled state by binding to `NgForm` validity.
- Controlling the *Submit* button's enabled state by binding to `NgForm` validity.
- Custom CSS classes that provide visual feedback to users about invalid controls.
Our final project folder structure should look like this:
The final project folder structure should look like this:
<aio-filetree>

View File

@ -38,7 +38,7 @@ The following diagram represents the state of the this guide's three-level compo
open simultaneously.
<figure class='image-display'>
<img src="/resources/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>
### Injector bubbling
@ -109,7 +109,7 @@ Each tax return component
* has the ability to save the changes to its tax return or cancel them.
<figure class='image-display'>
<img src="/resources/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>
One might suppose that the `TaxReturnComponent` has logic to manage and restore changes.
@ -166,7 +166,7 @@ that have special capabilites suitable for whatever is going on in component (B)
Component (B) is the parent of another component (C) that defines its own, even _more specialized_ provider for `CarService`.
<figure class='image-display'>
<img src="/resources/images/devguide/dependency-injection/car-components.png" alt="car components" width="220"> </img>
<img src="assets/images/devguide/dependency-injection/car-components.png" alt="car components" width="220"> </img>
</figure>
Behind the scenes, each component sets up its own injector with zero, one, or more providers defined for that component itself.
@ -176,7 +176,7 @@ its injector produces an instance of `Car` resolved by injector (C) with an `Eng
`Tires` resolved by the root injector (A).
<figure class='image-display'>
<img src="/resources/images/devguide/dependency-injection/injector-tree.png" alt="car injector tree" width="600"> </img>
<img src="assets/images/devguide/dependency-injection/injector-tree.png" alt="car injector tree" width="600"> </img>
</figure>

View File

@ -132,11 +132,14 @@ Each page includes code snippets from a sample application that accompanies the
You can reuse these snippets in your applications.
Look for a link to a running version of that sample, often near the top of the page,
such as this <live-example name="architecture"></live-example> from the [Architecture](architecture.html) page.
such as this <live-example nodownload name="architecture"></live-example> from the [Architecture](architecture.html) page.
<span if-docs="ts">
The link launches a browser-based, code editor where you can inspect, modify, save, and download the code.
</span>
Alternatively, you can run the example locally, next to those `live-example` links you have a <a href="/resources/zips/architecture/architecture.zip">download link</a>.
Just download, unzip, run `npm install` to install the dependencies and run it with `npm start`.
## Reference pages
* The [Cheat Sheet](cheatsheet.html) lists Angular syntax for common scenarios.

View File

@ -7,7 +7,7 @@ A suggested path through the documentation for Angular newcomers
@description
<figure>
<img src="/resources/images/devguide/intro/people.png" width="200px" height="152px" alt="Us" align="left" style="margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/intro/people.png" width="200px" height="152px" alt="Us" align="left" style="margin-left:-40px;margin-right:10px"> </img>
</figure>
Everyone learns differently.
@ -17,7 +17,7 @@ Those new to Angular may wish to follow this popular learning path.
1. [Setup](setup.html "Setup locally withe Quickstart seed") for local Angular development, if you haven't already done so.
1. Take the [*Tour of Heroes* tutorial](../tutorial "Tour of Heroes").
1. Take the [*Tour of Heroes* tutorial](../tutorial "Tour of Heroes").
The *Tour of Heroes* takes you step-by-step from [setup](setup.html)
to a full-featured example that demonstrates the essential characteristics of a professional application:
@ -42,5 +42,5 @@ After reading the above sections, feel free to skip around among the other pages
### Next Step
Try the [tutorial](../tutorial "Tour of Heroes") if you're ready to start coding or
Try the [tutorial](../tutorial "Tour of Heroes") if you're ready to start coding or
visit the [Architecture](architecture.html "Basic Concepts") page if you prefer to learn the basic concepts first.

View File

@ -7,7 +7,7 @@ Angular calls lifecycle hook methods on directives and components as it creates,
@description
<figure>
<img src="/resources/images/devguide/lifecycle-hooks/hooks-in-sequence.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:30px"> </img>
<img src="assets/images/devguide/lifecycle-hooks/hooks-in-sequence.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:30px"> </img>
</figure>
A component has a lifecycle managed by Angular itself.
@ -416,7 +416,7 @@ The peek-a-boo exists to show how Angular calls the hooks in the expected order.
This snapshot reflects the state of the log after the user clicked the *Create...* button and then the *Destroy...* button.
<figure class='image-display'>
<img src="/resources/images/devguide/lifecycle-hooks/peek-a-boo.png" alt="Peek-a-boo"> </img>
<img src="assets/images/devguide/lifecycle-hooks/peek-a-boo.png" alt="Peek-a-boo"> </img>
</figure>
The sequence of log messages follows the prescribed hook calling order:
@ -465,7 +465,7 @@ Each spy's birth and death marks the birth and death of the attached hero `<div>
with an entry in the *Hook Log* as seen here:
<figure class='image-display'>
<img src='/resources/images/devguide/lifecycle-hooks/spy-directive.gif' alt="Spy Directive"> </img>
<img src='assets/images/devguide/lifecycle-hooks/spy-directive.gif' alt="Spy Directive"> </img>
</figure>
Adding a hero results in a new hero `<div>`. The spy's `ngOnInit` logs that event.
@ -538,7 +538,7 @@ The host `OnChangesParentComponent` binds to them like this:
Here's the sample in action as the user makes changes.
<figure class='image-display'>
<img src='/resources/images/devguide/lifecycle-hooks/on-changes-anim.gif' alt="OnChanges"> </img>
<img src='assets/images/devguide/lifecycle-hooks/on-changes-anim.gif' alt="OnChanges"> </img>
</figure>
The log entries appear as the string value of the *power* property changes.
@ -561,7 +561,7 @@ It writes a special message to the log when there are no substantive changes to
so you can see how often `DoCheck` is called. The results are illuminating:
<figure class='image-display'>
<img src='/resources/images/devguide/lifecycle-hooks/do-check-anim.gif' alt="DoCheck"> </img>
<img src='assets/images/devguide/lifecycle-hooks/do-check-anim.gif' alt="DoCheck"> </img>
</figure>
While the `ngDoCheck` hook can detect when the hero's `name` has changed, it has a frightful cost.
@ -611,7 +611,7 @@ Both of these hooks fire _after_ the component's view has been composed.
Angular throws an error if the hook updates the component's data-bound `comment` property immediately (try it!).Here's *AfterView* in action
<figure class='image-display'>
<img src='/resources/images/devguide/lifecycle-hooks/after-view-anim.gif' alt="AfterView"> </img>
<img src='assets/images/devguide/lifecycle-hooks/after-view-anim.gif' alt="AfterView"> </img>
</figure>
Notice that Angular frequently calls `AfterViewChecked`, often when there are no changes of interest.
@ -644,7 +644,7 @@ The `<ng-content>` tag is a *placeholder* for the external content.
It tells Angular where to insert that content.
In this case, the projected content is the `<my-child>` from the parent.
<figure class='image-display'>
<img src='/resources/images/devguide/lifecycle-hooks/projected-child-view.png' width="230" alt="Projected Content"> </img>
<img src='assets/images/devguide/lifecycle-hooks/projected-child-view.png' width="230" alt="Projected Content"> </img>
</figure>

File diff suppressed because it is too large Load Diff

View File

@ -181,7 +181,7 @@ Now enter the `@Component` decorator that specifies the `HeroDetailComponent` me
{@example 'reactive-forms/ts/src/app/hero-detail.component.ts' region='metadata'}
The `moduleId: module.id` lets you use
[component-relative paths](./cookbook/component-relative-paths.html) in file URLs
[component-relative paths](../cookbook/component-relative-paths.html) in file URLs
such as when specifying the `templateUrl`.
Next, create an exported `HeroDetailComponent` class with a `FormControl`.
@ -285,7 +285,7 @@ Add the `bootstrap` _CSS stylesheet_ to the head of `index.html`:
Now that everything is wired up, the browser should display something like this:
<figure class='image-display'>
<img src="/resources/images/devguide/reactive-forms/just-formcontrol.png" width="400px" alt="Single FormControl"> </img>
<img src="assets/images/devguide/reactive-forms/just-formcontrol.png" width="400px" alt="Single FormControl"> </img>
</figure>
@ -357,7 +357,7 @@ The `heroForm.value` returns the _form model_.
Piping it through the `JsonPipe` renders the model as JSON in the browser:
<figure class='image-display'>
<img src="/resources/images/devguide/reactive-forms/json-output.png" width="400px" alt="JSON output"> </img>
<img src="assets/images/devguide/reactive-forms/json-output.png" width="400px" alt="JSON output"> </img>
</figure>
The initial `name` property value is the empty string.
@ -429,7 +429,7 @@ Configuring validation is harder in template-driven forms where you must wrap va
The browser displays the following:
<figure class='image-display'>
<img src="/resources/images/devguide/reactive-forms/validators-json-output.png" width="400px" alt="Single FormControl"> </img>
<img src="assets/images/devguide/reactive-forms/validators-json-output.png" width="400px" alt="Single FormControl"> </img>
</figure>
`Validators.required` is working. The status is `INVALID` because the input box has no value.
@ -527,7 +527,7 @@ After these changes, the JSON output in the browser shows the revised _form mode
with the nested address `FormGroup`:
<figure class='image-display'>
<img src="/resources/images/devguide/reactive-forms/address-group.png" width="400px" alt="JSON output"> </img>
<img src="assets/images/devguide/reactive-forms/address-group.png" width="400px" alt="JSON output"> </img>
</figure>
Great! Youve made a group and you can see that the template
@ -712,9 +712,9 @@ Take a moment to refactor the _address_ `FormGroup` definition for brevity and c
{@example 'reactive-forms/ts/src/app/hero-detail-7.component.ts' region='address-form-group'}
Also be sure to update the import from `data-model` so you can reference the `Hero` class:
Also be sure to update the import from `data-model` so you can reference the `Hero` and `Address` classes:
{@example 'reactive-forms/ts/src/app/hero-detail-6.component.ts' region='import-hero'}
{@example 'reactive-forms/ts/src/app/hero-detail-7.component.ts' region='import-address'}
@ -819,7 +819,7 @@ The `HeroDetailComponent` is a nested sub-component of the `HeroListComponent` i
Together they look a bit like this:
<figure class='image-display'>
<img src="/resources/images/devguide/reactive-forms/hero-list.png" width="420px" alt="HeroListComponent"> </img>
<img src="assets/images/devguide/reactive-forms/hero-list.png" width="420px" alt="HeroListComponent"> </img>
</figure>
The `HeroListComponent` uses an injected `HeroService` to retrieve heroes from the server
@ -844,8 +844,8 @@ The techniques involved are covered elsewhere in the documentation, including th
If you're coding along with the steps in this reactive forms tutorial,
create the pertinent files based on the
[source code displayed below](#source-code "Reactive Forms source code").
Notice that `hero-list.component.ts` and `hero-list.component.ts`
import `Observable` and `finally` from `rxjs`.
Notice that `hero-list.component.ts` imports `Observable` and `finally` while `hero.service.ts` imports `Observable`, `of`,
and `delay` from `rxjs`.
Then return here to learn about _form array_ properties.
@ -987,7 +987,7 @@ Back in the browser, select the hero named "Magneta".
"Magneta" doesn't have an address, as you can see in the diagnostic JSON at the bottom of the form.
<figure class='image-display'>
<img src="/resources/images/devguide/reactive-forms/addresses-array.png" width="400px" alt="JSON output of addresses array"> </img>
<img src="assets/images/devguide/reactive-forms/addresses-array.png" width="400px" alt="JSON output of addresses array"> </img>
</figure>
Click the "_Add a Secret Lair_" button.
@ -1046,7 +1046,7 @@ In a real app, you'd also be able to revert unsaved changes and resume editing.
After you implement both features in this section, the form will look like this:
<figure class='image-display'>
<img src="/resources/images/devguide/reactive-forms/save-revert-buttons.png" width="389px" alt="Form with save & revert buttons"> </img>
<img src="assets/images/devguide/reactive-forms/save-revert-buttons.png" width="389px" alt="Form with save & revert buttons"> </img>
</figure>
### Save

View File

@ -411,12 +411,12 @@ Once the app warms up, you'll see a row of navigation buttons
and the *Heroes* view with its list of heroes.
<figure class='image-display'>
<img src='/resources/images/devguide/router/hero-list.png' alt="Hero List" width="250"> </img>
<img src='assets/images/devguide/router/hero-list.png' alt="Hero List" width="250"> </img>
</figure>
Select one hero and the app takes you to a hero editing screen.
<figure class='image-display'>
<img src='/resources/images/devguide/router/hero-detail.png' alt="Crisis Center Detail" width="250"> </img>
<img src='assets/images/devguide/router/hero-detail.png' alt="Crisis Center Detail" width="250"> </img>
</figure>
Alter the name.
@ -430,7 +430,7 @@ Angular app navigation updates the browser history as normal web navigation does
Now click the *Crisis Center* link for a list of ongoing crises.
<figure class='image-display'>
<img src='/resources/images/devguide/router/crisis-center-list.png' alt="Crisis Center List" width="250"> </img>
<img src='assets/images/devguide/router/crisis-center-list.png' alt="Crisis Center List" width="250"> </img>
</figure>
Select a crisis and the application takes you to a crisis editing screen.
@ -440,7 +440,7 @@ Alter the name of a crisis.
Notice that the corresponding name in the crisis list does _not_ change.
<figure class='image-display'>
<img src='/resources/images/devguide/router/crisis-center-detail.png' alt="Crisis Center Detail" width="250"> </img>
<img src='assets/images/devguide/router/crisis-center-detail.png' alt="Crisis Center Detail" width="250"> </img>
</figure>
Unlike *Hero Detail*, which updates as you type,
@ -453,7 +453,7 @@ Click the browser back button or the "Heroes" link instead.
Up pops a dialog box.
<figure class='image-display'>
<img src='/resources/images/devguide/router/confirm-dialog.png' alt="Confirm Dialog" width="250"> </img>
<img src='assets/images/devguide/router/confirm-dialog.png' alt="Confirm Dialog" width="250"> </img>
</figure>
You can say "OK" and lose your changes or click "Cancel" and continue editing.
@ -470,7 +470,7 @@ Proceed to the first application milestone.
Begin with a simple version of the app that navigates between two empty views.
<figure class='image-display'>
<img src='/resources/images/devguide/router/router-1-anim.gif' alt="App in action" width="250"> </img>
<img src='assets/images/devguide/router/router-1-anim.gif' alt="App in action" width="250"> </img>
</figure>
@ -575,7 +575,7 @@ The root `AppComponent` is the application shell. It has a title, a navigation b
and a *router outlet* where the router swaps views on and off the page. Here's what you get:
<figure class='image-display'>
<img src='/resources/images/devguide/router/shell-and-outlet.png' alt="Shell" width="300"> </img>
<img src='assets/images/devguide/router/shell-and-outlet.png' alt="Shell" width="300"> </img>
</figure>
@ -930,7 +930,7 @@ from the <live-example name="toh-4" title="Tour of Heroes: Services example code
Here's how the user will experience this version of the app:
<figure class='image-display'>
<img src='/resources/images/devguide/router/router-2-anim.gif' alt="App in action"> </img>
<img src='assets/images/devguide/router/router-2-anim.gif' alt="App in action"> </img>
</figure>
A typical application has multiple *feature areas*,
@ -1325,7 +1325,7 @@ For example, when returning to the heroes list from the hero detail view,
it would be nice if the viewed hero was preselected in the list.
<figure class='image-display'>
<img src='/resources/images/devguide/router/selected-hero.png' alt="Selected hero"> </img>
<img src='assets/images/devguide/router/selected-hero.png' alt="Selected hero"> </img>
</figure>
You'll implement this feature in a moment by including the viewed hero's `id`
@ -1422,7 +1422,7 @@ The binding adds the `selected` CSS class when the method returns `true` and rem
Look for it within the repeated `<li>` tag as shown here:
When the user navigates from the heroes list to the "Magneta" hero and back, "Magneta" appears selected:
<figure class='image-display'>
<img src='/resources/images/devguide/router/selected-hero.png' alt="Selected List"> </img>
<img src='assets/images/devguide/router/selected-hero.png' alt="Selected List"> </img>
</figure>
The optional `foo` route parameter is harmless and continues to be ignored.
@ -1662,7 +1662,7 @@ You'll organize the crisis center to conform to the following recommended patter
If your app had many feature areas, the app component trees might look like this:
<figure class='image-display'>
<img src='/resources/images/devguide/router/component-tree.png' alt="Component Tree"> </img>
<img src='assets/images/devguide/router/component-tree.png' alt="Component Tree"> </img>
</figure>
### Child routing component
@ -1830,7 +1830,7 @@ It displays a simple form with a header, an input box for the message,
and two buttons, "Send" and "Cancel".
<figure class='image-display'>
<img src='/resources/images/devguide/router/contact-popup.png' alt="Contact popup" width="250"> </img>
<img src='assets/images/devguide/router/contact-popup.png' alt="Contact popup" width="250"> </img>
</figure>
Here's the component and its template:
@ -2507,7 +2507,7 @@ accessing the admin feature area.
It redirects to the login page if the user is not authorized.
But the router is still loading the `AdminModule` even if the user can't visit any of its components.
Ideally, you's only load the `AdminModule` if the user is logged in.
Ideally, you'd only load the `AdminModule` if the user is logged in.
Add a **`CanLoad`** guard that only loads the `AdminModule` once the user is logged in _and_ attempts to access the admin feature area.

View File

@ -5,21 +5,20 @@ Security
Developing for content security in Angular applications
@description
This section describes Angular's built-in
protections against common web application vulnerabilities and attacks such as cross-site
scripting attacks. It does not cover application-level security, such as authentication (_Who is
this user?_) or authorization (_What can this user do?_).
This page describes Angular's built-in
protections against common web-application vulnerabilities and attacks such as cross-site
scripting attacks. It doesn't cover application-level security, such as authentication (_Who is
this user?_) and authorization (_What can this user do?_).
For more information about the attacks and mitigations described below, see [OWASP Guide Project](https://www.owasp.org/index.php/Category:OWASP_Guide_Project).
Try the <live-example></live-example> of the code shown in this page.
You can run the <live-example></live-example> in Plunker and download the code from there.
<h2 id='report-issues'>
Reporting vulnerabilities
</h2>
Email us at [security@angular.io](mailto:security@angular.io) to report vulnerabilities in
Angular itself.
To report vulnerabilities in Angular itself, email us at [security@angular.io](mailto:security@angular.io).
For more information about how Google handles security issues, see [Google's security
philosophy](https://www.google.com/about/appsecurity/).
@ -30,7 +29,7 @@ philosophy](https://www.google.com/about/appsecurity/).
</h2>
* **Keep current with the latest Angular library releases.**
We regularly update our Angular libraries, and these updates may fix security defects discovered in
We regularly update the Angular libraries, and these updates may fix security defects discovered in
previous versions. Check the Angular [change
log](https://github.com/angular/angular/blob/master/CHANGELOG.md) for security-related updates.
@ -39,7 +38,8 @@ Private, customized versions of Angular tend to fall behind the current version
important security fixes and enhancements. Instead, share your Angular improvements with the
community and make a pull request.
* **Avoid Angular APIs marked in the documentation as “[_Security Risk_](#bypass-security-apis).”**
* **Avoid Angular APIs marked in the documentation as “_Security Risk_.”**
For more information, see the [Trusting safe values](#bypass-security-apis) section of this page.
<h2 id='xss'>
@ -48,79 +48,83 @@ community and make a pull request.
[Cross-site scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) enables attackers
to inject malicious code into web pages. Such code can then, for example, steal user data (in
particular, their login data) or perform actions impersonating the user. This is one of the most
particular, login data) or perform actions to impersonate the user. This is one of the most
common attacks on the web.
To block XSS attacks, you must prevent malicious code from entering the DOM (Document Object Model). For example, if an
attacker can trick you into inserting a `<script>` tag in the DOM, they can run arbitrary code on
your website. The attack is not limited to `<script>` tags&mdash;many elements and properties in the
To block XSS attacks, you must prevent malicious code from entering the DOM (Document Object Model). For example, if
attackers can trick you into inserting a `<script>` tag in the DOM, they can run arbitrary code on
your website. The attack isn't limited to `<script>` tags&mdash;many elements and properties in the
DOM allow code execution, for example, `<img onerror="...">` and `<a href="javascript:...">`. If
attacker-controlled data enters the DOM, expect security vulnerabilities.
### Angulars cross-site scripting security model
To systematically block XSS bugs, Angular treats all values as untrusted by default. When a value
is inserted into the DOM from a template, via property, attribute, style, class binding, or interpolation, Angular sanitizes and escapes untrusted values.
is inserted into the DOM from a template, via property, attribute, style, class binding, or interpolation,
Angular sanitizes and escapes untrusted values.
_Angular templates are the same as executable code_: HTML, attributes, and binding expressions
(but not the values bound!) in templates are trusted to be safe. This means that applications must
(but not the values bound) in templates are trusted to be safe. This means that applications must
prevent values that an attacker can control from ever making it into the source code of a
template. Never generate template source code by concatenating user input and templates! Using
the [offline template compiler](#offline-template-compiler) is an effective way to prevent these
vulnerabilities, also known as _template injection_.
template. Never generate template source code by concatenating user input and templates.
To prevent these vulnerabilities, use
the [offline template compiler](#offline-template-compiler), also known as _template injection_.
### Sanitization and security contexts
_Sanitization_ is the inspection of an untrusted value, turning it into a value that is safe to insert into
the DOM. In many cases, sanitization does not change a value at all. Sanitization depends on context:
a value that is harmless in CSS is potentially dangerous in a URL.
_Sanitization_ is the inspection of an untrusted value, turning it into a value that's safe to insert into
the DOM. In many cases, sanitization doesn't change a value at all. Sanitization depends on context:
a value that's harmless in CSS is potentially dangerous in a URL.
Angular defines four security contexts&mdash;HTML, style, URL, and resource URL:
Angular defines the following security contexts:
* **HTML** is used when interpreting a value as HTML, for example, when binding to `innerHtml`
* **Style** is used when binding CSS into the `style` property
* **URL** is used for URL properties such as `<a href>`
* **Resource URL** is a URL that will be loaded and executed as code, for example, in `<script src>`
* **HTML** is used when interpreting a value as HTML, for example, when binding to `innerHtml`.
* **Style** is used when binding CSS into the `style` property.
* **URL** is used for URL properties, such as `<a href>`.
* **Resource URL** is a URL that will be loaded and executed as code, for example, in `<script src>`.
Angular sanitizes untrusted values for the first three items; sanitizing resource URLs is not
Angular sanitizes untrusted values for HTML, styles, and URLs; sanitizing resource URLs isn't
possible because they contain arbitrary code. In development mode, Angular prints a console warning
when it has to change a value during sanitization.
### Sanitization example
The template below binds the value of `htmlSnippet`, once by interpolating it into an element's
The following template binds the value of `htmlSnippet`, once by interpolating it into an element's
content, and once by binding it to the `innerHTML` property of an element:
{@example 'security/ts/src/app/inner-html-binding.component.html'}
Interpolated content is always escaped&mdash;the HTML is not interpreted, and the browser displays
Interpolated content is always escaped&mdash;the HTML isn't interpreted and the browser displays
angle brackets in the element's text content.
For the HTML to be interpreted, you must bind it to an HTML property such as `innerHTML`. But binding
For the HTML to be interpreted, bind it to an HTML property such as `innerHTML`. But binding
a value that an attacker might control into `innerHTML` normally causes an XSS
vulnerability. For example, code contained in a `<script>` tag is executed:
### Avoid direct use of the DOM APIs
The built-in browser DOM APIs do not automatically protect you from security vulnerabilities.
The built-in browser DOM APIs don't automatically protect you from security vulnerabilities.
For example, `document`, the node available through `ElementRef`, and many third-party APIs
contain unsafe methods. Avoid directly interacting with the DOM and instead use Angular
templates where possible.
### Content security policy
[Content Security Policy (CSP)](http://www.html5rocks.com/en/tutorials/security/content-security-policy/) is a defense-in-depth
Content Security Policy (CSP) is a defense-in-depth
technique to prevent XSS. To enable CSP, configure your web server to return an appropriate
`Content-Security-Policy` HTTP header.
`Content-Security-Policy` HTTP header. Read more about content security policy at
[An Introduction to Content Security Policy](http://www.html5rocks.com/en/tutorials/security/content-security-policy/)
on the HTML5Rocks website.
<a id="offline-template-compiler"></a>
### Use the offline template compiler
The offline template compiler prevents a whole class of vulnerabilities called template injection,
and also greatly improves application performance. Use the offline template compiler in production
deployments; do not dynamically generate templates. Angular trusts template code, so generating
templates, in particular templates containing user data, circumvents Angular's built-in protections. For information about how to dynamically construct forms in a safe way, see
[Dynamic Forms Cookbook](../cookbook/dynamic-form.html).
and greatly improves application performance. Use the offline template compiler in production
deployments; don't dynamically generate templates. Angular trusts template code, so generating
templates, in particular templates containing user data, circumvents Angular's built-in protections.
For information about dynamically constructing forms in a safe way, see the
[Dynamic Forms](../cookbook/dynamic-form.html) cookbook page.
### Server-side XSS protection
@ -128,12 +132,12 @@ HTML constructed on the server is vulnerable to injection attacks. Injecting tem
Angular application is the same as injecting executable code into the
application: it gives the attacker full control over the application. To prevent this,
use a templating language that automatically escapes values to prevent XSS vulnerabilities on
the server. Do not generate Angular templates on the server side using a templating language; doing this
the server. Don't generate Angular templates on the server side using a templating language; doing this
carries a high risk of introducing template-injection vulnerabilities.
<h2 id='code-review'>
Auditing angular applications
Auditing Angular applications
</h2>
Angular applications must follow the same security principles as regular web applications, and

View File

@ -69,7 +69,7 @@ The app uses the !{_Angular_Http} client to communicate via `XMLHttpRequest (XHR
It works like this:
<figure class='image-display'>
<img src='/resources/images/devguide/server-communication/http-toh.gif' alt="ToH mini app" width="250"> </img>
<img src='assets/images/devguide/server-communication/http-toh.gif' alt="ToH mini app" width="250"> </img>
</figure>
This demo has a single component, the `HeroListComponent`. Here's its template:
@ -279,7 +279,7 @@ Here is a simple search that shows suggestions from Wikipedia as the user
types in a text box:
<figure class='image-display'>
<img src='/resources/images/devguide/server-communication/wiki-1.gif' alt="Wikipedia search app (v.1)" width="250"> </img>
<img src='assets/images/devguide/server-communication/wiki-1.gif' alt="Wikipedia search app (v.1)" width="250"> </img>
</figure>

View File

@ -119,7 +119,7 @@ The `ngIf` directive doesn't hide elements with CSS. It adds and removes them ph
Confirm that fact using browser developer tools to inspect the DOM.
<figure class='image-display'>
<img src='/resources/images/devguide/structural-directives/element-not-in-dom.png' alt="ngIf=false element not in DOM"> </img>
<img src='assets/images/devguide/structural-directives/element-not-in-dom.png' alt="ngIf=false element not in DOM"> </img>
</figure>
The top paragraph is in the DOM. The bottom, disused paragraph is not;
@ -139,7 +139,7 @@ A directive could hide the unwanted paragraph instead by setting its `display` s
While invisible, the element remains in the DOM.
<figure class='image-display'>
<img src='/resources/images/devguide/structural-directives/element-display-in-dom.png' alt="hidden element still in DOM"> </img>
<img src='assets/images/devguide/structural-directives/element-display-in-dom.png' alt="hidden element still in DOM"> </img>
</figure>
The difference between hiding and removing doesn't matter for a simple paragraph.
@ -201,7 +201,7 @@ You also have a CSS style rule that happens to apply to a `<span>` within a `<p>
The constructed paragraph renders strangely.
<figure class='image-display'>
<img src='/resources/images/devguide/structural-directives/bad-paragraph.png' alt="spanned paragraph with bad style"> </img>
<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.
@ -216,7 +216,7 @@ When you try this,
the drop down is empty.
<figure class='image-display'>
<img src='/resources/images/devguide/structural-directives/bad-select.png' alt="spanned options don't work"> </img>
<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>`.
@ -232,7 +232,7 @@ Here's the conditional paragraph again, this time using `<ng-container>`.
It renders properly.
<figure class='image-display'>
<img src='/resources/images/devguide/structural-directives/good-paragraph.png' alt="ngcontainer paragraph with proper style"> </img>
<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>`.
@ -241,7 +241,7 @@ Now conditionally exclude a _select_ `<option>` with `<ng-container>`.
The drop down works properly.
<figure class='image-display'>
<img src='/resources/images/devguide/structural-directives/select-ngcontainer-anim.gif' alt="ngcontainer options work properly"> </img>
<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.
@ -289,7 +289,7 @@ Then it translates the template _attribute_ into a template _element_, wrapped a
None of these forms are actually rendered.
Only the finished product ends up in the DOM.
<figure class='image-display'>
<img src='/resources/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>
Angular consumed the `<template>` content during its actual rendering and
@ -390,7 +390,7 @@ variable as the `hero` declared as `#hero`.
{@a one-per-element}
### One structural directive per host element
Someday you'll want to to repeat a block of HTML but only when a particular condition is true.
Someday you'll want to repeat a block of HTML but only when a particular condition is true.
You'll _try_ to put both an `*ngFor` and an `*ngIf` on the same host element.
Angular won't let you. You may apply only one _structural_ directive to an element.
@ -469,7 +469,7 @@ 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.
<figure class='image-display'>
<img src='/resources/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>
A structural directive puts a `<template>` to work
@ -554,7 +554,7 @@ Then create some HTML to try it.
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.
<figure class='image-display'>
<img src='/resources/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>

View File

@ -74,7 +74,7 @@ The guideline will use the shortcut `hero.component.ts|html|css|spec` to represe
## Single responsibility
Apply the
<a href="https://wikipedia.org/wiki/Single_responsibility_principle" target="_blank"><i>Single Responsibility Principle</i> (SPR)</a>
<a href="https://wikipedia.org/wiki/Single_responsibility_principle" target="_blank"><i>Single Responsibility Principle</i> (SRP)</a>
to all components, services, and other symbols.
This helps make the app cleaner, easier to read and maintain, and more testable.
@ -248,7 +248,7 @@ Naming conventions are hugely important to maintainability and readability. This
<div class='s-why'>
**Why?** The naming conventions should simply help find desited code faster and make it easier to understand.
**Why?** The naming conventions should simply help find desired code faster and make it easier to understand.
</div>

View File

@ -887,7 +887,7 @@ nor property binding.
Interpolation handles the script tags differently than property binding but both approaches render the
content harmlessly.
<figure class='image-display'>
<img src='/resources/images/devguide/template-syntax/evil-title.png' alt="evil title made safe" width='500px'> </img>
<img src='assets/images/devguide/template-syntax/evil-title.png' alt="evil title made safe" width='500px'> </img>
</figure>
&nbsp;<a href="#toc">back to top</a>
@ -1353,7 +1353,7 @@ The following contrived example forces the input value to uppercase:
Here are all variations in action, including the uppercase version:
<figure class='image-display'>
<img src='/resources/images/devguide/template-syntax/ng-model-anim.gif' alt="NgModel variations"> </img>
<img src='assets/images/devguide/template-syntax/ng-model-anim.gif' alt="NgModel variations"> </img>
</figure>
&nbsp;
@ -1555,7 +1555,7 @@ Here is an illustration of the _trackBy_ effect.
* With `trackBy`, only changing the `id` triggers element replacement.
<figure class='image-display'>
<img src='/resources/images/devguide/template-syntax/ng-for-track-by-anim.gif' alt="trackBy"> </img>
<img src='assets/images/devguide/template-syntax/ng-for-track-by-anim.gif' alt="trackBy"> </img>
</figure>
<a href="#toc">back to top</a>
@ -1579,7 +1579,7 @@ Angular puts only the *selected* element into the DOM.
<figure class='image-display'>
<img src='/resources/images/devguide/template-syntax/switch-anim.gif' alt="trackBy"> </img>
<img src='assets/images/devguide/template-syntax/switch-anim.gif' alt="trackBy"> </img>
</figure>
`NgSwitch` is the controller directive. Bind it to an expression that returns the *switch value*.
@ -1753,7 +1753,7 @@ Don't do both!### Input or output?
The terms _input_ and _output_ reflect the perspective of the target directive.
<figure class='image-display'>
<img src='/resources/images/devguide/template-syntax/input-output.png' alt="Inputs and outputs"> </img>
<img src='assets/images/devguide/template-syntax/input-output.png' alt="Inputs and outputs"> </img>
</figure>
`HeroDetailComponent.hero` is an **input** property from the perspective of `HeroDetailComponent`

View File

@ -309,7 +309,7 @@ everything work seamlessly:
use in AngularJS.
<figure class='image-display'>
<img src="/resources/images/devguide/upgrade/injectors.png" alt="The two injectors in a hybrid application" width="700"> </img>
<img src="assets/images/devguide/upgrade/injectors.png" alt="The two injectors in a hybrid application" width="700"> </img>
</figure>
#### Components and the DOM
@ -349,7 +349,7 @@ ways:
and Angular content projection together.
<figure class='image-display'>
<img src="/resources/images/devguide/upgrade/dom.png" alt="DOM element ownership in a hybrid application" width="500"> </img>
<img src="assets/images/devguide/upgrade/dom.png" alt="DOM element ownership in a hybrid application" width="500"> </img>
</figure>
Whenever we use a component that belongs to the other framework, a
@ -395,7 +395,7 @@ AngularJS and Angular approaches. Here's what happens:
detection after every event.
<figure class='image-display'>
<img src="/resources/images/devguide/upgrade/change_detection.png" alt="Change detection in a hybrid application" width="600"> </img>
<img src="assets/images/devguide/upgrade/change_detection.png" alt="Change detection in a hybrid application" width="600"> </img>
</figure>
What this means in practice is that we do not need to call `$apply()` in
@ -491,7 +491,7 @@ Congratulations! You're running a hybrid application! The
existing AngularJS code works as before _and_ you're ready to run Angular code.
### Using Angular Components from AngularJS Code
<figure>
<img src="/resources/images/devguide/upgrade/ajs-to-a.png" alt="Using an Angular component from AngularJS code" align="left" style="width:250px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/upgrade/ajs-to-a.png" alt="Using an Angular component from AngularJS code" align="left" style="width:250px; margin-left:-40px;margin-right:10px"> </img>
</figure>
Once we're running a hybrid app, we can start the gradual process of upgrading
@ -523,7 +523,7 @@ Angular module.
All Angular components, directives and pipes must be declared in an NgModule.
The net resulit is an AngularJS directive called `heroDetail`, that we can
The net result is an AngularJS directive called `heroDetail`, that we can
use like any other directive in our AngularJS templates.
@ -602,7 +602,7 @@ For example, we can easily make multiple copies of the component using `ng-repe
### Using AngularJS Component Directives from Angular Code
<figure>
<img src="/resources/images/devguide/upgrade/a-to-ajs.png" alt="Using an AngularJS component from Angular code" align="left" style="width:250px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/upgrade/a-to-ajs.png" alt="Using an AngularJS component from Angular code" align="left" style="width:250px; margin-left:-40px;margin-right:10px"> </img>
</figure>
So, we can write an Angular component and then use it from AngularJS
@ -781,7 +781,7 @@ and then provide the input and output using Angular template syntax:
### Projecting AngularJS Content into Angular Components
<figure>
<img src="/resources/images/devguide/upgrade/ajs-to-a-with-projection.png" alt="Projecting AngularJS content into Angular" align="left" style="width:250px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/upgrade/ajs-to-a-with-projection.png" alt="Projecting AngularJS content into Angular" align="left" style="width:250px; margin-left:-40px;margin-right:10px"> </img>
</figure>
When we are using a downgraded Angular component from an AngularJS
@ -815,7 +815,7 @@ remains in "AngularJS land" and is managed by the AngularJS framework.
### Transcluding Angular Content into AngularJS Component Directives
<figure>
<img src="/resources/images/devguide/upgrade/a-to-ajs-with-transclusion.png" alt="Projecting Angular content into AngularJS" align="left" style="width:250px; margin-left:-40px;margin-right:10px"> </img>
<img src="assets/images/devguide/upgrade/a-to-ajs-with-transclusion.png" alt="Projecting Angular content into AngularJS" align="left" style="width:250px; margin-left:-40px;margin-right:10px"> </img>
</figure>
Just like we can project AngularJS content into Angular components,
@ -1657,7 +1657,7 @@ Now set the remaining `phone-detail.component.ts` as follows:
This is similar to the phone list component.
The new wrinkle is the `RouteParams` type annotation that identifies the `routeParams` dependency.
The AngularJS injector has an AngularJS router dependency called `$routeParams`.
The AngularJS injector has an AngularJS router dependency called `$routeParams`,
which was injected into `PhoneDetails` when it was still an AngularJS controller.
We intend to inject it into the new `PhoneDetailsComponent`.

View File

@ -74,7 +74,7 @@ Here's what the UI displays:
<figure class='image-display'>
<img src='/resources/images/devguide/user-input/keyup1-anim.gif' alt="key up 1"> </img>
<img src='assets/images/devguide/user-input/keyup1-anim.gif' alt="key up 1"> </img>
</figure>
@ -134,7 +134,7 @@ and the component does nothing.
Type something in the input box, and watch the display update with each keystroke.
<figure class='image-display'>
<img src='/resources/images/devguide/user-input/keyup-loop-back-anim.gif' alt="loop back"> </img>
<img src='assets/images/devguide/user-input/keyup-loop-back-anim.gif' alt="loop back"> </img>
</figure>
@ -166,7 +166,7 @@ Then Angular calls the event handler only when the user presses _Enter_.
Here's how it works.
<figure class='image-display'>
<img src='/resources/images/devguide/user-input/keyup3-anim.gif' alt="key up 3"> </img>
<img src='assets/images/devguide/user-input/keyup3-anim.gif' alt="key up 3"> </img>
</figure>
@ -193,7 +193,7 @@ The user can add a hero by typing the hero's name in the input box and
clicking **Add**.
<figure class='image-display'>
<img src='/resources/images/devguide/user-input/little-tour-anim.gif' alt="Little Tour of Heroes"> </img>
<img src='assets/images/devguide/user-input/little-tour-anim.gif' alt="Little Tour of Heroes"> </img>
</figure>
Below is the "Little Tour of Heroes" component.

View File

@ -38,7 +38,9 @@ This guide offers a taste of Webpack and explains how to use it with Angular app
[Trying it out](#try)
[Conclusions](#conclusions)
You can also <a href="/resources/zips/webpack/webpack.zip">download the final result.</a>
<a id="what-is-webpack"></a>## What is Webpack?
Webpack is a powerful module bundler.
@ -156,7 +158,7 @@ Create a **new project folder**
</code-example>
Add these files to the root directory:
Add these files:
<md-tab-group>
@ -165,8 +167,8 @@ Add these files to the root directory:
</md-tab>
<md-tab label="tsconfig.json">
{@example 'webpack/ts/tsconfig.1.json'}
<md-tab label="src/tsconfig.json">
{@example 'webpack/ts/src/tsconfig.1.json'}
</md-tab>
@ -304,9 +306,9 @@ Rules tell Webpack which loaders to use for each file (AKA _module_):
* html - for component templates
* images/fonts - Images and fonts are bundled as well.
* css - The pattern matches application-wide styles; the second handles component-scoped styles (the ones specified in a component's `styleUrls` metadata property)
The first pattern excludes `.css` files within the `/src/app` directories where the component-scoped styles sit.
It includes only `.css` files located at or above `/src`; these are the application-wide styles.
The `ExtractTextPlugin` (described below) applies the `style` and `css` loaders to these files.
The first pattern is for the application-wide styles. It excludes `.css` files within the `src/app` directory
where the component-scoped styles sit. The `ExtractTextPlugin` (described below) applies the `style` and `css`
loaders to these files.
The second pattern filters for component-scoped styles and loads them as strings via the `raw` loader &mdash;
which is what Angular expects to do with styles specified in a `styleUrls` metadata property.
@ -484,8 +486,8 @@ Webpack techniques covered in this guide.
</md-tab>
<md-tab label="public/css/styles.css">
{@example 'webpack/ts/public/css/styles.css'}
<md-tab label="src/assets/css/styles.css">
{@example 'webpack/ts/src/assets/css/styles.css'}
</md-tab>
@ -521,14 +523,10 @@ Webpack techniques covered in this guide.
</md-tab-group>
<p>
The <code>app.component.html</code> displays this downloadable Angular logo
<a href="https://raw.githubusercontent.com/angular/angular.io/master/public/resources/images/logos/angular2/angular.png" target="_blank">
<img src="/resources/images/logos/angular2/angular.png" height="40px" title="download Angular logo"></a>.
</p>
The <code>app.component.html</code> displays this downloadable Angular logo
<a href="https://raw.githubusercontent.com/angular/angular.io/master/publicassets/images/logos/angular2/angular.png" target="_blank">
<img src="assets/images/logos/angular2/angular.png" height="40px" title="download Angular logo"></a>.
Create folder `images` under the project's "assets" folder, then right-click and download the image to that folder.
{@a bundle-ts}

View File

@ -34,7 +34,7 @@ Here's a visual idea of where we're going in this tour, beginning with the "Dash
view and our most heroic heroes:
<figure class='image-display'>
<img src='/resources/images/devguide/toh/heroes-dashboard-1.png' alt="Output of heroes dashboard"> </img>
<img src='assets/images/devguide/toh/heroes-dashboard-1.png' alt="Output of heroes dashboard"> </img>
</figure>
Above the dashboard are two links ("Dashboard" and "Heroes").
@ -44,7 +44,7 @@ Instead we click the dashboard hero named "Magneta" and the router takes us to a
of that hero where we can change the hero's name.
<figure class='image-display'>
<img src='/resources/images/devguide/toh/hero-details-1.png' alt="Details of hero in app"> </img>
<img src='assets/images/devguide/toh/hero-details-1.png' alt="Details of hero in app"> </img>
</figure>
Clicking the "Back" button would return us to the "Dashboard".
@ -52,7 +52,7 @@ Links at the top can take us to either of the main views.
We'll click "Heroes". The app takes to the "Heroes" master list view.
<figure class='image-display'>
<img src='/resources/images/devguide/toh/heroes-list-2.png' alt="Output of heroes list app"> </img>
<img src='assets/images/devguide/toh/heroes-list-2.png' alt="Output of heroes list app"> </img>
</figure>
We click a different hero and the readonly mini-detail beneath the list reflects our new choice.
@ -63,13 +63,13 @@ editable details of our selected hero.
The following diagram captures all of our navigation options.
<figure class='image-display'>
<img src='/resources/images/devguide/toh/nav-diagram.png' alt="View navigations"> </img>
<img src='assets/images/devguide/toh/nav-diagram.png' alt="View navigations"> </img>
</figure>
Here's our app in action
<figure class='image-display'>
<img src='/resources/images/devguide/toh/toh-anim.gif' alt="Tour of Heroes in Action"> </img>
<img src='assets/images/devguide/toh/toh-anim.gif' alt="Tour of Heroes in Action"> </img>
</figure>

View File

@ -306,7 +306,7 @@ For example, when we select Magneta from the heroes list,
we can make it pop out visually by giving it a subtle background color as shown here.
<figure class='image-display'>
<img src='/resources/images/devguide/toh/heroes-list-selected.png' alt="Selected hero"> </img>
<img src='assets/images/devguide/toh/heroes-list-selected.png' alt="Selected hero"> </img>
</figure>
Well add a property binding on `class` for the `selected` class to the template. We'll set this to an expression that compares the current `selectedHero` to the `hero`.
@ -329,7 +329,7 @@ The browser reloads our app.
We select the hero Magneta and the selection is clearly identified by the background color.
<figure class='image-display'>
<img src='/resources/images/devguide/toh/heroes-list-1.png' alt="Output of heroes list app"> </img>
<img src='assets/images/devguide/toh/heroes-list-1.png' alt="Output of heroes list app"> </img>
</figure>
We select a different hero and the tell-tale color switches to that hero.

View File

@ -15,7 +15,7 @@ We received new requirements for our Tour of Heroes application:
When were done, users will be able to navigate the app like this:
<figure class='image-display'>
<img src='/resources/images/devguide/toh/nav-diagram.png' alt="View navigations"> </img>
<img src='assets/images/devguide/toh/nav-diagram.png' alt="View navigations"> </img>
</figure>
We'll add Angulars *Router* to our app to satisfy these requirements.
@ -93,6 +93,27 @@ Instead of displaying heroes automatically, we'd like to show them *after* the u
In other words, we'd like to navigate to the list of heroes.
We'll need the Angular *Router*.
### *&lt;base href>*
Open `index.html` and ensure there is a `<base href="...">` element
(or a script that dynamically sets this element)
at the top of the `<head>` section.
~~~ {.callout.is-important}
<header>
base href is essential
</header>
See the *base href* section of the [router](../guide/router.html#base-href)
guide to learn why this matters, and what to add if the `base`
element is missing.
~~~
{@a configure-routes}
@ -322,7 +343,7 @@ Although the dashboard heroes are presented as button-like blocks, they should b
When hovering over a hero block, the target URL should display in the browser status bar
and the user should be able to copy the link or open the hero detail view in a new tab.
To achieve this effect, reopen the `dashboard.component.html` and replace the repeated `<div *ngFor...>` tags
To achieve this effect, reopen the <span ngio-ex>dashboard.component.html</span> and replace the repeated `<div *ngFor...>` tags
with `<a>` tags. The opening `<a>` tag looks like this:
@ -374,7 +395,7 @@ Add the following HTML fragment at the bottom of the template where the `<my-her
After clicking a hero, the user should see something like this below the hero list:
<figure class='image-display'>
<img src='/resources/images/devguide/toh/mini-hero-detail.png' alt="Mini Hero Detail" height="70"> </img>
<img src='assets/images/devguide/toh/mini-hero-detail.png' alt="Mini Hero Detail" height="70"> </img>
</figure>
### Format with the *uppercase* pipe
@ -420,7 +441,7 @@ back in the `DashboardComponent`.
Here's the fully revised `HeroesComponent` class:
Refresh the browser and start clicking.
We can navigate around the app, from the dashboard to hero details and back,
for heroes list to the mini-detail to the hero details and back to the heroes again.
from heroes list to the mini-detail to the hero details and back to the heroes again.
We can jump back and forth between the dashboard and the heroes.
We've met all of the navigational requirements that propelled this chapter.
@ -478,7 +499,7 @@ If necessary, also edit <span ngio-ex>index.html</span> to refer to this stylesh
Look at the app now. Our dashboard, heroes, and navigation links are styling!
<figure class='image-display'>
<img src='/resources/images/devguide/toh/dashboard-top-heroes.png' alt="View navigations"> </img>
<img src='assets/images/devguide/toh/dashboard-top-heroes.png' alt="View navigations"> </img>
</figure>

View File

@ -266,7 +266,7 @@ Run the app again, go to the *Dashboard*, and enter some text in the search box.
At some point it might look like this.
<figure class='image-display'>
<img src='/resources/images/devguide/toh/toh-hero-search.png' alt="Hero Search Component"> </img>
<img src='assets/images/devguide/toh/toh-hero-search.png' alt="Hero Search Component"> </img>
</figure>