chore(aio): blank line before each list-item; - becomes * (#3481)

This commit is contained in:
Ward Bell 2017-03-31 15:25:27 -07:00 committed by Jesús Rodríguez
parent 5738c4b66a
commit a56c4a0b08
40 changed files with 660 additions and 448 deletions

View File

@ -288,16 +288,6 @@ include ../../../_includes/_util-fns
+makeJson('styleguide/package.1.json', {paths: 'dependencies'}, "package.json dependencies", { pnk: [/(\S*zone.*)/, /(\Score-js.*)/, /(\Ssystem.*)/ ]}) +makeJson('styleguide/package.1.json', {paths: 'dependencies'}, "package.json dependencies", { pnk: [/(\S*zone.*)/, /(\Score-js.*)/, /(\Ssystem.*)/ ]})
:marked
As well as styling across multiple lines.
code-example(format="" language="js").
- var styles = { pnk: /(^.*dependencies[\s\S]* \})/gm };
+makeJson('styleguide/package.1.json', {paths: 'name, version, dependencies '}, "Foo", styles )
- var styles = { pnk: /(^.*dependencies[\s\S]* \})/gm };
+makeJson('styleguide/package.1.json', {paths: 'name, version, dependencies '}, "Foo", styles )
:marked :marked
### Inline code and code examples provided directly i.e. not from an example file. ### Inline code and code examples provided directly i.e. not from an example file.
@ -307,10 +297,10 @@ include ../../../_includes/_util-fns
This style has several named attributes This style has several named attributes
#### code-example attributes #### code-example attributes
- *name:* Name displayed in Tab (required for tabs) * *name:* Name displayed in Tab (required for tabs)
- *language:* javascript, html, etc. * *language:* javascript, html, etc.
- *escape:* html (escapes html, woot!) * *escape:* html (escapes html, woot!)
- *format:* linenums (or linenums:4 specify starting line) * *format:* linenums (or linenums:4 specify starting line)
#### Example #### Example

View File

@ -17,17 +17,17 @@ include ../_util-fns
We will build a simple form from scratch, one step at a time. Along the way we'll learn 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 * How to build an Angular form with a component and template
- The `ngModel` two-way data binding syntax for reading and writing values to input controls * The `ngModel` two-way data binding syntax for reading and writing values to input controls
- The `ngModel` directive in combination with a form to track the change state and validity of form controls * The `ngModel` directive in combination with a form to track the change state and validity of form controls
- The Special CSS classes that follow the state of the controls and can be used to provide strong visual feedback * The Special CSS classes that follow the state of the controls and can be used to provide strong visual feedback
- How to display validation errors to users and enable/disable form controls * How to display validation errors to users and enable/disable form controls
- How to share information across controls with template local variables * How to share information across controls with template local variables
<live-example>Live Example</live-example> <live-example>Live Example</live-example>
@ -148,18 +148,19 @@ code-example(format="").
Understanding this component requires only the Angular concepts weve learned in previous chapters Understanding this component requires only the Angular concepts weve learned in previous chapters
1. We use the `ng.core` object from the Angular library as we usually do. * We use the `ng.core` object from the Angular library as we usually do.
1. The `Component()` selector value of "hero-form" means we can drop this form in a parent template with a `<hero-form>` tag. * The `Component()` selector value of "hero-form" means we can drop this form in a parent template with a `<hero-form>` tag.
1. The `templateUrl` property points to a separate file for template HTML called `hero-form.component.html`. * The `templateUrl` property points to a separate file for template HTML called `hero-form.component.html`.
1. We defined dummy data for `model` and `powers` as befits a demo. * 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 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 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. parent component. None of this concerns us now and these future changes won't affect our form.
1. We threw in a `diagnostic` method at the end to return a JSON representation of our model. * We threw in a `diagnostic` method at the end 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. It'll help us see what we're doing during our development; we've left ourselves a cleanup note to discard it later.
Why don't we write the template inline in the component file as we often do Why don't we write the template inline in the component file as we often do

View File

@ -663,8 +663,9 @@ table(width="100%")
+makeExample('cb-ajs-quick-reference/ts/src/app/app.module.1.ts')(format=".") +makeExample('cb-ajs-quick-reference/ts/src/app/app.module.1.ts')(format=".")
:marked :marked
Angular modules, defined with the `NgModule` decorator, serve the same purpose: Angular modules, defined with the `NgModule` decorator, serve the same purpose:
- `imports`: specifies the list of other modules that this module depends upon
- `declaration`: keeps track of your components, pipes, and directives. * `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 (NgModule)](../guide/ngmodule.html). For more information on modules, see [Angular Modules (NgModule)](../guide/ngmodule.html).
tr(style=top) tr(style=top)

View File

@ -8,25 +8,30 @@ a#toc
:marked :marked
# Contents # Contents
- [Overview](overview) * [Overview](overview)
- [Ahead-of-time (AOT) vs just-in-time (JIT)](#aot-jit) * [Ahead-of-time (AOT) vs just-in-time (JIT)](#aot-jit)
- [Why do AOT compilation?](#why-aot) * [Why do AOT compilation?](#why-aot)
- [Compile with AOT](#compile) * [Compile with AOT](#compile)
- [Bootstrap](#bootstrap) * [Bootstrap](#bootstrap)
- [Tree shaking](#tree-shaking) * [Tree shaking](#tree-shaking)
- [Rollup](#rollup)
- [Rollup Plugins](#rollup-plugins) *[Rollup](#rollup)
- [Run Rollup](#run-rollup) *[Rollup Plugins](#rollup-plugins)
- [Load the bundle](#load) *[Run Rollup](#run-rollup)
- [Serve the app](#serve)
- [AOT QuickStart source code](#source-code) * [Load the bundle](#load)
- [Workflow and convenience script](#workflow) * [Serve the app](#serve)
- [Develop JIT along with AOT](#run-jit) * [AOT QuickStart source code](#source-code)
- [Tour of Heroes](#toh) * [Workflow and convenience script](#workflow)
- [JIT in development, AOT in production](#jit-dev-aot-prod)
- [Tree shaking](#shaking) *[Develop JIT along with AOT](#run-jit)
- [Running the application](#running-app)
- [Inspect the Bundle](#inspect-bundle) * [Tour of Heroes](#toh)
*[JIT in development, AOT in production](#jit-dev-aot-prod)
*[Tree shaking](#shaking)
*[Running the application](#running-app)
*[Inspect the Bundle](#inspect-bundle)
a#overview a#overview

View File

@ -15,11 +15,11 @@ include ../_util-fns
:marked :marked
# Contents # Contents
- [Pass data from parent to child with input binding](#parent-to-child) * [Pass data from parent to child with input binding](#parent-to-child)
- [Intercept input property changes with a setter](#parent-to-child-setter) * [Intercept input property changes with a setter](#parent-to-child-setter)
- [Intercept input property changes with `ngOnChanges()`](#parent-to-child-on-changes) * [Intercept input property changes with `ngOnChanges()`](#parent-to-child-on-changes)
- [Parent calls an `@ViewChild()`](#parent-to-view-child) * [Parent calls an `@ViewChild()`](#parent-to-view-child)
- [Parent and children communicate via a service](#bidirectional-service) * [Parent and children communicate via a service](#bidirectional-service)
:marked :marked

View File

@ -337,7 +337,6 @@ figure.image-display
The following image shows the effect of mousing over the `<hero-bios-and-contacts>` tag. The following image shows the effect of mousing over the `<hero-bios-and-contacts>` tag.
figure.image-display figure.image-display
img(src="/resources/images/cookbooks/dependency-injection/highlight.png" alt="Highlighted bios") img(src="/resources/images/cookbooks/dependency-injection/highlight.png" alt="Highlighted bios")
:marked
<a id="providers"></a> <a id="providers"></a>
.l-main-section .l-main-section
@ -847,7 +846,6 @@ a(id="provideparent")
:marked :marked
And here's how we could use it with a different parent type: And here's how we could use it with a different parent type:
+makeExample('cb-dependency-injection/ts/src/app/parent-finder.component.ts','beth-providers')(format='.') +makeExample('cb-dependency-injection/ts/src/app/parent-finder.component.ts','beth-providers')(format='.')
:marked
a(id="forwardref") a(id="forwardref")
.l-main-section .l-main-section

View File

@ -17,17 +17,24 @@ a#toc
* [Simple template-driven forms](#template1) * [Simple template-driven forms](#template1)
* [Template-driven forms with validation messages in code](#template2) * [Template-driven forms with validation messages in code](#template2)
- [Component Class](#component-class)
- [The benefits of messages in code](#improvement) * [Component Class](#component-class)
- [`FormModule` and template-driven forms](#formmodule) * [The benefits of messages in code](#improvement)
* [`FormModule` and template-driven forms](#formmodule)
* [Reactive forms with validation in code](#reactive) * [Reactive forms with validation in code](#reactive)
- [Switch to the `ReactiveFormsModule`](#reactive-forms-module)
- [Component template](#reactive-component-template) * [Switch to the `ReactiveFormsModule`](#reactive-forms-module)
- [Component class](#reactive-component-class) * [Component template](#reactive-component-template)
- [`FormBuilder` declaration](#formbuilder) * [Component class](#reactive-component-class)
- [Committing hero value changes](#committing-changes)
* [`FormBuilder` declaration](#formbuilder)
* [Committing hero value changes](#committing-changes)
* [Custom validation](#custom-validation) * [Custom validation](#custom-validation)
- [Custom validation directive](#custom-validation-directive)
* [Custom validation directive](#custom-validation-directive)
* [Testing considerations](#testing) * [Testing considerations](#testing)
a#live-example a#live-example
@ -60,22 +67,23 @@ a#template1
:marked :marked
Note the following: Note the following:
- The `<input>` element carries the HTML validation attributes: `required`, `minlength`, and `maxlength`.
- The `name` attribute of the input is set to `"name"` so Angular can track this input element and associate it * The `<input>` element carries the HTML validation attributes: `required`, `minlength`, and `maxlength`.
* The `name` attribute of the input is set to `"name"` so Angular can track this input element and associate it
with an Angular form control called `name` in its internal control model. with an Angular form control called `name` in its internal control model.
- The `[(ngModel)]` directive allows two-way data binding between the input box to the `hero.name` property. * The `[(ngModel)]` directive allows two-way data binding between the input box to the `hero.name` property.
- The template variable (`#name`) has the value `"ngModel"` (always `ngModel`). * The template variable (`#name`) has the value `"ngModel"` (always `ngModel`).
This gives you a reference to the Angular `NgModel` directive This gives you a reference to the Angular `NgModel` directive
associated with this control that you can use _in the template_ associated with this control that you can use _in the template_
to check for control states such as `valid` and `dirty`. to check for control states such as `valid` and `dirty`.
- The `*ngIf` on the `<div>` element reveals a set of nested message `divs` but only if there are "name" errors and * The `*ngIf` on the `<div>` element reveals a set of nested message `divs` but only if there are "name" errors and
the control is either `dirty` or `touched`. the control is either `dirty` or `touched`.
- Each nested `<div>` can present a custom message for one of the possible validation errors. * Each nested `<div>` can present a custom message for one of the possible validation errors.
There are messages for `required`, `minlength`, and `maxlength`. There are messages for `required`, `minlength`, and `maxlength`.
The full template repeats this kind of layout for each data entry control on the form. The full template repeats this kind of layout for each data entry control on the form.
@ -136,16 +144,17 @@ a#template2
:marked :marked
The `<input>` element HTML is almost the same. There are noteworthy differences: The `<input>` element HTML is almost the same. There are noteworthy differences:
- The hard-code error message `<divs>` are gone.
- There's a new attribute, `forbiddenName`, that is actually a custom validation directive. * The hard-code error message `<divs>` are gone.
* There's a new attribute, `forbiddenName`, that is actually a custom validation directive.
It invalidates the control if the user enters "bob" in the name `<input>`([try it](#live-example)). It invalidates the control if the user enters "bob" in the name `<input>`([try it](#live-example)).
See the [custom validation](#custom-validation) section later in this cookbook for more information See the [custom validation](#custom-validation) section later in this cookbook for more information
on custom validation directives. on custom validation directives.
- The `#name` template variable is gone because the app no longer refers to the Angular control for this element. * The `#name` template variable is gone because the app no longer refers to the Angular control for this element.
- Binding to the new `formErrors.name` property is sufficent to display all name validation error messages. * Binding to the new `formErrors.name` property is sufficent to display all name validation error messages.
a#component-class a#component-class
:marked :marked
@ -169,17 +178,17 @@ a#component-class
:marked :marked
Some observations: Some observations:
- Angular `@ViewChild` queries for a template variable when you pass it * Angular `@ViewChild` queries for a template variable when you pass it
the name of that variable as a string (`'heroForm'` in this case). the name of that variable as a string (`'heroForm'` in this case).
- The `heroForm` object changes several times during the life of the component, most notably when you add a new hero. * The `heroForm` object changes several times during the life of the component, most notably when you add a new hero.
Periodically inspecting it reveals these changes. Periodically inspecting it reveals these changes.
- Angular calls the `ngAfterViewChecked` [lifecycle hook method](../guide/lifecycle-hooks.html#afterview) * Angular calls the `ngAfterViewChecked` [lifecycle hook method](../guide/lifecycle-hooks.html#afterview)
when anything changes in the view. when anything changes in the view.
That's the right time to see if there's a new `heroForm` object. That's the right time to see if there's a new `heroForm` object.
- When there _is_ a new `heroForm` model, `formChanged()` subscribes to its `valueChanges` _Observable_ property. * When there _is_ a new `heroForm` model, `formChanged()` subscribes to its `valueChanges` _Observable_ property.
The `onValueChanged` handler looks for validation errors after every keystroke. The `onValueChanged` handler looks for validation errors after every keystroke.
+makeExample('cb-form-validation/ts/src/app/template/hero-form-template2.component.ts','handler','template/hero-form-template2.component.ts (handler)')(format='.') +makeExample('cb-form-validation/ts/src/app/template/hero-form-template2.component.ts','handler','template/hero-form-template2.component.ts (handler)')(format='.')
@ -193,9 +202,9 @@ a#component-class
The messages are empty strings when the hero data are valid. The messages are empty strings when the hero data are valid.
For each field, the `onValueChanged` handler does the following: For each field, the `onValueChanged` handler does the following:
- Clears the prior error message, if any. * Clears the prior error message, if any.
- Acquires the field's corresponding Angular form control. * Acquires the field's corresponding Angular form control.
- If such a control exists _and_ it's been changed ("dirty") * If such a control exists _and_ it's been changed ("dirty")
_and_ it's invalid, the handler composes a consolidated error message for all of the control's errors. _and_ it's invalid, the handler composes a consolidated error message for all of the control's errors.
Next, the component needs some error messages of course&mdash;a set for each validated property with Next, the component needs some error messages of course&mdash;a set for each validated property with
@ -266,6 +275,7 @@ a#reactive
This approach requires a bit more effort. *You have to write the control model and manage it*. This approach requires a bit more effort. *You have to write the control model and manage it*.
This allows you to do the following: This allows you to do the following:
* Add, change, and remove validation functions on the fly. * Add, change, and remove validation functions on the fly.
* Manipulate the control model dynamically from within the component. * Manipulate the control model dynamically from within the component.
* [Test](#testing) validation and control logic with isolated unit tests. * [Test](#testing) validation and control logic with isolated unit tests.
@ -303,10 +313,10 @@ a#reactive-component-template
:marked :marked
Key changes are: Key changes are:
- The validation attributes are gone (except `required`) because * The validation attributes are gone (except `required`) because
validating happens in code. validating happens in code.
- `required` remains, not for validation purposes (that's in the code), * `required` remains, not for validation purposes (that's in the code),
but rather for css styling and accessibility. but rather for css styling and accessibility.
.l-sub-section .l-sub-section
@ -318,10 +328,10 @@ a#reactive-component-template
to the control model, as you'll see below. to the control model, as you'll see below.
:marked :marked
- The `formControlName` replaces the `name` attribute; it serves the same * The `formControlName` replaces the `name` attribute; it serves the same
purpose of correlating the input with the Angular form control. purpose of correlating the input with the Angular form control.
- The two-way `[(ngModel)]` binding is gone. * The two-way `[(ngModel)]` binding is gone.
The reactive approach does not use data binding to move data into and out of the form controls. The reactive approach does not use data binding to move data into and out of the form controls.
That's all in code. That's all in code.
@ -346,15 +356,15 @@ a#reactive-component-class
`reactive/hero-form-reactive.component.ts (FormBuilder), `reactive/hero-form-reactive.component.ts (FormBuilder),
template/hero-form-template2.component.ts (ViewChild)`) template/hero-form-template2.component.ts (ViewChild)`)
:marked :marked
- Inject `FormBuilder` in a constructor. * Inject `FormBuilder` in a constructor.
- Call a `buildForm` method in the `ngOnInit` [lifecycle hook method](../guide/lifecycle-hooks.html#hooks-overview) * Call a `buildForm` method in the `ngOnInit` [lifecycle hook method](../guide/lifecycle-hooks.html#hooks-overview)
because that's when you'll have the hero data. Call it again in the `addHero` method. because that's when you'll have the hero data. Call it again in the `addHero` method.
.l-sub-section .l-sub-section
:marked :marked
A real app would retrieve the hero asynchronously from a data service, a task best performed in the `ngOnInit` hook. A real app would retrieve the hero asynchronously from a data service, a task best performed in the `ngOnInit` hook.
:marked :marked
- The `buildForm` method uses the `FormBuilder`, `fb`, to declare the form control model. * The `buildForm` method uses the `FormBuilder`, `fb`, to declare the form control model.
Then it attaches the same `onValueChanged` handler (there's a one line difference) Then it attaches the same `onValueChanged` handler (there's a one line difference)
to the form's `valueChanges` event and calls it immediately to the form's `valueChanges` event and calls it immediately
to set error messages for the new control model. to set error messages for the new control model.
@ -387,6 +397,7 @@ a#committing-changes
The developer decides _when and how_ to update the data model from control values. The developer decides _when and how_ to update the data model from control values.
This sample updates the model twice: This sample updates the model twice:
1. When the user submits the form. 1. When the user submits the form.
1. When the user adds a new hero. 1. When the user adds a new hero.

View File

@ -14,8 +14,10 @@ a#top
* [Create a translation source file with the **_ng-xi18n_ extraction tool**](#ng-xi18n) * [Create a translation source file with the **_ng-xi18n_ extraction tool**](#ng-xi18n)
* [Translate text messages](#translate) * [Translate text messages](#translate)
* [Merge the completed translation file into the app](#merge) * [Merge the completed translation file into the app](#merge)
* [Merge with the JIT compiler](#jit) * [Merge with the JIT compiler](#jit)
* [Internationalization with the AOT compiler](#aot) * [Internationalization with the AOT compiler](#aot)
* [Translation file maintenance and _id_ changes](#maintenance) * [Translation file maintenance and _id_ changes](#maintenance)
:marked :marked
@ -164,6 +166,7 @@ a#cardinality
categories and their matching values. categories and their matching values.
Pluralization categories include: Pluralization categories include:
* =0 * =0
* =1 * =1
* =5 * =5
@ -172,6 +175,7 @@ a#cardinality
Put the default _English_ translation in braces (`{}`) next to the pluralization category. Put the default _English_ translation in braces (`{}`) next to the pluralization category.
* When you're talking about one wolf, you could write `=1 {one wolf}`. * When you're talking about one wolf, you could write `=1 {one wolf}`.
* For zero wolves, you could write `=0 {no wolves}`. * For zero wolves, you could write `=0 {no wolves}`.
* For two wolves, you could write `=2 {two wolves}`. * For two wolves, you could write `=2 {two wolves}`.
@ -421,6 +425,7 @@ a#merge
in another format (`.xlif` and `.xtb`) that Angular understands. in another format (`.xlif` and `.xtb`) that Angular understands.
You provide the Angular compiler with three new pieces of information: You provide the Angular compiler with three new pieces of information:
* the translation file * the translation file
* the translation file format * the translation file format
* the <a href="https://en.wikipedia.org/wiki/XLIFF" target="_blank">_Locale ID_</a> * the <a href="https://en.wikipedia.org/wiki/XLIFF" target="_blank">_Locale ID_</a>
@ -477,6 +482,7 @@ a#text-plugin
creates those providers based on the user's _locale_ creates those providers based on the user's _locale_
and the corresponding translation file: and the corresponding translation file:
+makeExample('cb-i18n/ts/src/app/i18n-providers.ts', null, 'src/app/i18n-providers.ts') +makeExample('cb-i18n/ts/src/app/i18n-providers.ts', null, 'src/app/i18n-providers.ts')
:marked :marked
1. It gets the locale from the global `document.locale` variable that was set in `index.html`. 1. It gets the locale from the global `document.locale` variable that was set in `index.html`.
@ -541,6 +547,7 @@ a#aot
The result is a separate version of the application for each language. The result is a separate version of the application for each language.
Tell AOT how to translate by adding three options to the `ngc` command: Tell AOT how to translate by adding three options to the `ngc` command:
* `--i18nFile`: the path to the translation file * `--i18nFile`: the path to the translation file
* `--locale`: the name of the locale * `--locale`: the name of the locale
* `--i18nFormat`: the format of the localization file * `--i18nFormat`: the format of the localization file

View File

@ -95,6 +95,7 @@ a#q-what-not-to-declare
Add only [declarable](#q-declarable) classes to a module's `declarations` list. Add only [declarable](#q-declarable) classes to a module's `declarations` list.
Do *not* declare the following: Do *not* declare the following:
* A class that's already declared in another module, whether an app module, @NgModule, or third-party module. * A class that's already declared in another module, whether an app module, @NgModule, or third-party module.
* An array of directives imported from another module. * An array of directives imported from another module.
For example, don't declare FORMS_DIRECTIVES from `@angular/forms`. For example, don't declare FORMS_DIRECTIVES from `@angular/forms`.
@ -560,7 +561,6 @@ a#q-is-it-loaded
Certain NgModules (such as `BrowserModule`) implement such a guard, Certain NgModules (such as `BrowserModule`) implement such a guard,
such as this `CoreModule` constructor from the NgModules page. such as this `CoreModule` constructor from the NgModules page.
+makeExample('ngmodule/ts/src/app/core/core.module.ts', 'ctor', 'src/app/core/core.module.ts (Constructor)')(format='.') +makeExample('ngmodule/ts/src/app/core/core.module.ts', 'ctor', 'src/app/core/core.module.ts (Constructor)')(format='.')
:marked
.l-hr .l-hr
@ -597,6 +597,7 @@ a#q-entry-component-defined
You must tell it about them by adding them to the `entryComponents` list. You must tell it about them by adding them to the `entryComponents` list.
Angular automatically adds the following types of components to the module's `entryComponents`: Angular automatically adds the following types of components to the module's `entryComponents`:
* The component in the `@NgModule.bootstrap` list. * The component in the `@NgModule.bootstrap` list.
* Components referenced in router configuration. * Components referenced in router configuration.
@ -723,6 +724,7 @@ a#q-module-recommendations
Create feature modules around specific application business domains, user workflows, and utility collections. Create feature modules around specific application business domains, user workflows, and utility collections.
Feature modules tend to fall into one of the following groups: Feature modules tend to fall into one of the following groups:
* [Domain feature modules](#domain-feature-module). * [Domain feature modules](#domain-feature-module).
* [Routed feature modules](#routed-feature-module). * [Routed feature modules](#routed-feature-module).
* [Routing modules](#routing-module). * [Routing modules](#routing-module).
@ -803,6 +805,7 @@ table
A routing module separates routing concerns from its companion module. A routing module separates routing concerns from its companion module.
A routing module typically does the following: A routing module typically does the following:
* Defines routes. * Defines routes.
* Adds router configuration to the module's `imports`. * Adds router configuration to the module's `imports`.
* Re-exports `RouterModule`. * Re-exports `RouterModule`.
@ -1159,6 +1162,7 @@ table
The `RouterModule` adds routed components to that list. The `RouterModule` adds routed components to that list.
That leaves only the following sources of undiscoverable components: That leaves only the following sources of undiscoverable components:
* Components bootstrapped using one of the imperative techniques. * Components bootstrapped using one of the imperative techniques.
* Components dynamically loaded into the DOM by some means other than the router. * Components dynamically loaded into the DOM by some means other than the router.

View File

@ -40,6 +40,7 @@ a#from-ts
The transformation of _TypeScript_ code all the way down to _ES5_ code can be seen as "shedding" features. The transformation of _TypeScript_ code all the way down to _ES5_ code can be seen as "shedding" features.
The downgrade progression is The downgrade progression is
* _TypeScript_ to _ES6-with-decorators_ * _TypeScript_ to _ES6-with-decorators_
* _ES6-with-decorators_ to _ES6-without-decorators_ ("_plain ES6_") * _ES6-with-decorators_ to _ES6-without-decorators_ ("_plain ES6_")
* _ES6-without-decorators_ to _ES5_ * _ES6-without-decorators_ to _ES5_
@ -488,6 +489,7 @@ a#io-decorators
In _TypeScript_ and _ES6-with-decorators_, In _TypeScript_ and _ES6-with-decorators_,
you precede the constructor parameters with injection qualifiers such as: you precede the constructor parameters with injection qualifiers such as:
* [`@Optional`](../api/core/index/Optional-decorator.html) sets the parameter to `null` if the service is missing * [`@Optional`](../api/core/index/Optional-decorator.html) sets the parameter to `null` if the service is missing
* [`@Attribute`](../api/core/index/Attribute-interface.html) to inject a host element attribute value * [`@Attribute`](../api/core/index/Attribute-interface.html) to inject a host element attribute value
* [`@ContentChild`](../api/core/index/ContentChild-decorator.html) to inject a content child * [`@ContentChild`](../api/core/index/ContentChild-decorator.html) to inject a content child

View File

@ -27,15 +27,15 @@ include ../_util-fns
:marked :marked
The steps are as follows: The steps are as follows:
- [Prerequisite](#prereq1): Install Node.js * [Prerequisite](#prereq1): Install Node.js
- [Prerequisite](#prereq2): Install Visual Studio 2015 Update 3 * [Prerequisite](#prereq2): Install Visual Studio 2015 Update 3
- [Prerequisite](#prereq3): Configure External Web tools * [Prerequisite](#prereq3): Configure External Web tools
- [Prerequisite](#prereq4): Install TypeScript 2 for Visual Studio 2015 * [Prerequisite](#prereq4): Install TypeScript 2 for Visual Studio 2015
- [Step 1](#download): Download the QuickStart files * [Step 1](#download): Download the QuickStart files
- [Step 2](#create-project): Create the Visual Studio ASP.NET project * [Step 2](#create-project): Create the Visual Studio ASP.NET project
- [Step 3](#copy): Copy the QuickStart files into the ASP.NET project folder * [Step 3](#copy): Copy the QuickStart files into the ASP.NET project folder
- [Step 4](#restore): Restore required packages * [Step 4](#restore): Restore required packages
- [Step 5](#build-and-run): Build and run the app * [Step 5](#build-and-run): Build and run the app
.l-main-section .l-main-section
h2#prereq1 Prerequisite: Node.js h2#prereq1 Prerequisite: Node.js
@ -81,6 +81,7 @@ h2#prereq4 Prerequisite: Install TypeScript 2 for Visual Studio 2015
which you need to develop Angular applications. which you need to develop Angular applications.
To install TypeScript 2: To install TypeScript 2:
* Download and install **[TypeScript 2.0 for Visual Studio 2015](http://download.microsoft.com/download/6/D/8/6D8381B0-03C1-4BD2-AE65-30FF0A4C62DA/TS2.0.3-TS-release20-nightly-20160921.1/TypeScript_Dev14Full.exe)** * Download and install **[TypeScript 2.0 for Visual Studio 2015](http://download.microsoft.com/download/6/D/8/6D8381B0-03C1-4BD2-AE65-30FF0A4C62DA/TS2.0.3-TS-release20-nightly-20160921.1/TypeScript_Dev14Full.exe)**
* OR install it with npm: `npm install -g typescript@2.0`. * OR install it with npm: `npm install -g typescript@2.0`.
@ -121,6 +122,7 @@ h2#copy Step 3: Copy the QuickStart files into the ASP.NET project folder
* Click the `Show All Files` button in Solution Explorer to reveal all of the hidden files in the project. * Click the `Show All Files` button in Solution Explorer to reveal all of the hidden files in the project.
* Right-click on each folder/file to be included in the project and select `Include in Project`. * Right-click on each folder/file to be included in the project and select `Include in Project`.
Minimally, include the following folder/files: Minimally, include the following folder/files:
* app folder (answer *No* if asked to search for TypeScript Typings) * app folder (answer *No* if asked to search for TypeScript Typings)
* styles.css * styles.css
* index.html * index.html

View File

@ -181,6 +181,7 @@ a#component
operations and supporting declaration syntax. operations and supporting declaration syntax.
Read about the following forms of binding in the [Template Syntax](./template-syntax.html) page: Read about the following forms of binding in the [Template Syntax](./template-syntax.html) page:
* [Interpolation](./template-syntax.html#interpolation). * [Interpolation](./template-syntax.html#interpolation).
* [Property binding](./template-syntax.html#property-binding). * [Property binding](./template-syntax.html#property-binding).
* [Event binding](./template-syntax.html#event-binding). * [Event binding](./template-syntax.html#event-binding).
@ -417,6 +418,7 @@ a#jit
For example, the `OnInit` interface has a hook method named `ngOnInit`. For example, the `OnInit` interface has a hook method named `ngOnInit`.
Angular calls these hook methods in the following order: Angular calls these hook methods in the following order:
* `ngOnChanges`: when an [input](#input)/[output](#output) binding value changes. * `ngOnChanges`: when an [input](#input)/[output](#output) binding value changes.
* `ngOnInit`: after the first `ngOnChanges`. * `ngOnInit`: after the first `ngOnChanges`.
* `ngDoCheck`: developer's custom change detection. * `ngDoCheck`: developer's custom change detection.
@ -436,9 +438,10 @@ a#jit
.alert.is-important .alert.is-important
:marked :marked
Angular has the following types of modules: Angular has the following types of modules:
- [Angular modules](#angular-module).
* [Angular modules](#angular-module).
For details and examples, see the [Angular Modules](./ngmodule.html) page. For details and examples, see the [Angular Modules](./ngmodule.html) page.
- ES2015 modules, as described in this section. * ES2015 modules, as described in this section.
:marked :marked
A cohesive block of code dedicated to a single purpose. A cohesive block of code dedicated to a single purpose.
@ -538,10 +541,11 @@ a#Q
The alternative technique is [template-driven forms](#template-driven-forms). The alternative technique is [template-driven forms](#template-driven-forms).
When building reactive forms: When building reactive forms:
- The "source of truth" is the component. The validation is defined using code in the component.
- Each control is explicitly created in the component class with `new FormControl()` or with `FormBuilder`. * The "source of truth" is the component. The validation is defined using code in the component.
- The template input elements do *not* use `ngModel`. * Each control is explicitly created in the component class with `new FormControl()` or with `FormBuilder`.
- The associated Angular directives are all prefixed with `Form`, such as `FormGroup`, `FormControl`, and `FormControlName`. * The template input elements do *not* use `ngModel`.
* The associated Angular directives are all prefixed with `Form`, such as `FormGroup`, `FormControl`, and `FormControlName`.
Reactive forms are powerful, flexible, and a good choice for more complex data-entry form scenarios, such as dynamic generation of form controls. Reactive forms are powerful, flexible, and a good choice for more complex data-entry form scenarios, such as dynamic generation of form controls.
@ -658,10 +662,11 @@ a#structural-directives
The alternate technique is [Reactive Forms](#reactive-forms). The alternate technique is [Reactive Forms](#reactive-forms).
When building template-driven forms: When building template-driven forms:
- The "source of truth" is the template. The validation is defined using attributes on the individual input elements.
- [Two-way binding](#data-binding) with `ngModel` keeps the component model synchronized with the user's entry into the input elements. * The "source of truth" is the template. The validation is defined using attributes on the individual input elements.
- Behind the scenes, Angular creates a new control for each input element, provided you have set up a `name` attribute and two-way binding for each input. * [Two-way binding](#data-binding) with `ngModel` keeps the component model synchronized with the user's entry into the input elements.
- The associated Angular directives are all prefixed with `ng` such as `ngForm`, `ngModel`, and `ngModelGroup`. * Behind the scenes, Angular creates a new control for each input element, provided you have set up a `name` attribute and two-way binding for each input.
* The associated Angular directives are all prefixed with `ng` such as `ngForm`, `ngModel`, and `ngModelGroup`.
Template-driven forms are convenient, quick, and simple. They are a good choice for many basic data-entry form scenarios. Template-driven forms are convenient, quick, and simple. They are a good choice for many basic data-entry form scenarios.

View File

@ -249,15 +249,15 @@ figure
Here are a few of the most useful `@Component` configuration options: Here are a few of the most useful `@Component` configuration options:
:marked :marked
- `selector`: CSS selector that tells Angular to create and insert an instance of this component * `selector`: CSS selector that tells Angular to create and insert an instance of this component
where it finds a `<hero-list>` tag in *parent* HTML. where it finds a `<hero-list>` tag in *parent* HTML.
For example, if an app's HTML contains `<hero-list></hero-list>`, then For example, if an app's HTML contains `<hero-list></hero-list>`, then
Angular inserts an instance of the `HeroListComponent` view between those tags. Angular inserts an instance of the `HeroListComponent` view between those tags.
- `templateUrl`: module-relative address of this component's HTML template, shown [above](#templates). * `templateUrl`: module-relative address of this component's HTML template, shown [above](#templates).
:marked :marked
- `providers`: array of **dependency injection providers** for services that the component requires. * `providers`: array of **dependency injection providers** for services that the component requires.
This is one way to tell Angular that the component's constructor requires a `HeroService` This is one way to tell Angular that the component's constructor requires a `HeroService`
so it can get the list of heroes to display. so it can get the list of heroes to display.
@ -404,6 +404,7 @@ figure
<br class="l-clear-both"> <br class="l-clear-both">
:marked :marked
Examples include: Examples include:
* logging service * logging service
* data service * data service
* message bus * message bus

View File

@ -358,10 +358,10 @@ figure.image-display
This page covered how to: This page covered how to:
- [Build an **attribute directive**](#write-directive) that modifies the behavior of an element. * [Build an **attribute directive**](#write-directive) that modifies the behavior of an element.
- [Apply the directive](#apply-directive) to an element in a template. * [Apply the directive](#apply-directive) to an element in a template.
- [Respond to **events**](#respond-to-user) that change the directive's behavior. * [Respond to **events**](#respond-to-user) that change the directive's behavior.
- [**Bind** values to the directive](#bindings). * [**Bind** values to the directive](#bindings).
The final source code follows: The final source code follows:

View File

@ -37,6 +37,7 @@ block includes
the QuickStart repo update instructions</a>. the QuickStart repo update instructions</a>.
Notably: Notably:
* `app/main.ts` moved to `src/main.ts`. * `app/main.ts` moved to `src/main.ts`.
* `app/` moved to `src/app/`. * `app/` moved to `src/app/`.
* `index.html`, `styles.css` and `tsconfig.json` moved inside `src/`. * `index.html`, `styles.css` and `tsconfig.json` moved inside `src/`.
@ -52,15 +53,18 @@ block includes
choosing the approach that best fits each scenario. choosing the approach that best fits each scenario.
## NEW: Deployment guide (2017-01-30) ## NEW: Deployment guide (2017-01-30)
The new [Deployment](deployment.html) guide describes techniques for putting your application on a server. The new [Deployment](deployment.html) guide describes techniques for putting your application on a server.
It includes important advice on optimizing for production. It includes important advice on optimizing for production.
## Hierarchical Dependency Injection: refreshed (2017-01-13) ## Hierarchical Dependency Injection: refreshed (2017-01-13)
[Hierarchical Dependency Injection](hierarchical-dependency-injection.html) guide is significantly revised. [Hierarchical Dependency Injection](hierarchical-dependency-injection.html) guide is significantly revised.
Closes issue #3086. Closes issue #3086.
Revised samples are clearer and cover all topics discussed. Revised samples are clearer and cover all topics discussed.
## Miscellaneous (2017-01-05) ## Miscellaneous (2017-01-05)
* [Setup](setup.html) guide: * [Setup](setup.html) guide:
added (optional) instructions on how to remove _non-essential_ files. added (optional) instructions on how to remove _non-essential_ files.
* No longer consolidate RxJS operator imports in `rxjs-extensions` file; each file should import what it needs. * No longer consolidate RxJS operator imports in `rxjs-extensions` file; each file should import what it needs.
@ -68,28 +72,34 @@ block includes
* [Style Guide](style-guide.html): copy edits and revised rules. * [Style Guide](style-guide.html): copy edits and revised rules.
## Router: more detail (2016-12-21) ## Router: more detail (2016-12-21)
Added more information to the [Router](router.html) guide Added more information to the [Router](router.html) guide
including sections named outlets, wildcard routes, and preload strategies. including sections named outlets, wildcard routes, and preload strategies.
## HTTP: how to set default request headers (and other request options) (2016-12-14) ## HTTP: how to set default request headers (and other request options) (2016-12-14)
Added section on how to set default request headers (and other request options) to Added section on how to set default request headers (and other request options) to
[HTTP](server-communication.html#override-default-request-options) guide. [HTTP](server-communication.html#override-default-request-options) guide.
## Testing: added component test plunkers (2016-12-02) ## Testing: added component test plunkers (2016-12-02)
Added two plunkers that each test _one simple component_ so you can write a component test plunker of your own: <live-example name="setup" plnkr="quickstart-specs">one</live-example> for the QuickStart seed's `AppComponent` and <live-example name="testing" plnkr="banner-specs">another</live-example> for the Testing guide's `BannerComponent`. Added two plunkers that each test _one simple component_ so you can write a component test plunker of your own: <live-example name="setup" plnkr="quickstart-specs">one</live-example> for the QuickStart seed's `AppComponent` and <live-example name="testing" plnkr="banner-specs">another</live-example> for the Testing guide's `BannerComponent`.
Linked to these plunkers in [Testing](testing.html#live-examples) and [Setup anatomy](setup-systemjs-anatomy) guides. Linked to these plunkers in [Testing](testing.html#live-examples) and [Setup anatomy](setup-systemjs-anatomy) guides.
## Internationalization: pluralization and _select_ (2016-11-30) ## Internationalization: pluralization and _select_ (2016-11-30)
The [Internationalization (i18n)](../cookbook/i18n.html) guide explains how to handle pluralization and The [Internationalization (i18n)](../cookbook/i18n.html) guide explains how to handle pluralization and
translation of alternative texts with `select`. translation of alternative texts with `select`.
The sample demonstrates these features too. The sample demonstrates these features too.
## Testing: karma file updates (2016-11-30) ## Testing: karma file updates (2016-11-30)
* `karma.config` + `karma-test-shim` can handle multiple spec source paths; * `karma.config` + `karma-test-shim` can handle multiple spec source paths;
see quickstart issue: [angular/quickstart#294](https://github.com/angular/quickstart/issues/294). see quickstart issue: [angular/quickstart#294](https://github.com/angular/quickstart/issues/294).
* Displays Jasmine Runner output in the karma-launched browser. * Displays Jasmine Runner output in the karma-launched browser.
## QuickStart Rewrite (2016-11-18) ## QuickStart Rewrite (2016-11-18)
The QuickStart is completely rewritten so that it actually is quick. The QuickStart is completely rewritten so that it actually is quick.
It references a minimal "Hello Angular" app running in Plunker. It references a minimal "Hello Angular" app running in Plunker.
The new [Setup](setup.html) page tells you how to install a local development environment The new [Setup](setup.html) page tells you how to install a local development environment
@ -97,9 +107,11 @@ block includes
You are no longer asked to copy-and-paste code into setup files that were not explained anyway. You are no longer asked to copy-and-paste code into setup files that were not explained anyway.
## Sync with Angular v.2.2.0 (2016-11-14) ## Sync with Angular v.2.2.0 (2016-11-14)
Docs and code samples updated and tested with Angular v.2.2.0. Docs and code samples updated and tested with Angular v.2.2.0.
## UPDATE: NgUpgrade Guide for the AOT friendly _upgrade/static_ module (2016-11-14) ## UPDATE: NgUpgrade Guide for the AOT friendly _upgrade/static_ module (2016-11-14)
The updated [NgUpgrade Guide](upgrade.html) guide covers the The updated [NgUpgrade Guide](upgrade.html) guide covers the
new AOT friendly `upgrade/static` module new AOT friendly `upgrade/static` module
released in v.2.2.0, which is the recommended released in v.2.2.0, which is the recommended
@ -107,15 +119,18 @@ block includes
The documentation for the version prior to v.2.2.0 has been removed. The documentation for the version prior to v.2.2.0 has been removed.
## ES6 described in "TypeScript to JavaScript" (2016-11-14) ## ES6 described in "TypeScript to JavaScript" (2016-11-14)
The updated [TypeScript to JavaScript](../cookbook/ts-to-js.html) cookbook The updated [TypeScript to JavaScript](../cookbook/ts-to-js.html) cookbook
now explains how to write apps in ES6/7 now explains how to write apps in ES6/7
by translating the common idioms in the TypeScript documentation examples by translating the common idioms in the TypeScript documentation examples
(and elsewhere on the web) to ES6/7 and ES5. (and elsewhere on the web) to ES6/7 and ES5.
## Sync with Angular v.2.1.1 (2016-10-21) ## Sync with Angular v.2.1.1 (2016-10-21)
Docs and code samples updated and tested with Angular v.2.1.1. Docs and code samples updated and tested with Angular v.2.1.1.
## npm _@types_ packages replace _typings_ (2016-10-20) ## npm _@types_ packages replace _typings_ (2016-10-20)
Documentation samples now get TypeScript type information for 3rd party libraries Documentation samples now get TypeScript type information for 3rd party libraries
from npm `@types` packages rather than with the _typings_ tooling. from npm `@types` packages rather than with the _typings_ tooling.
The `typings.json` file is gone. The `typings.json` file is gone.
@ -125,34 +140,41 @@ block includes
packages in support of upgrade; these are not needed for pure Angular development. packages in support of upgrade; these are not needed for pure Angular development.
## "Template Syntax" explains two-way data binding syntax (2016-10-20) ## "Template Syntax" explains two-way data binding syntax (2016-10-20)
Demonstrates how to two-way data bind to a custom Angular component and Demonstrates how to two-way data bind to a custom Angular component and
re-explains `[(ngModel)]` in terms of the basic `[()]` syntax. re-explains `[(ngModel)]` in terms of the basic `[()]` syntax.
## BREAKING CHANGE: `in-memory-web-api` (v.0.1.11) delivered as esm umd (2016-10-19) ## BREAKING CHANGE: `in-memory-web-api` (v.0.1.11) delivered as esm umd (2016-10-19)
This change supports ES6 developers and aligns better with typical Angular libraries. This change supports ES6 developers and aligns better with typical Angular libraries.
It does not affect the module's API but it does affect how you load and import it. It does not affect the module's API but it does affect how you load and import it.
See the <a href="https://github.com/angular/in-memory-web-api/blob/master/CHANGELOG.md#0113-2016-10-20" target="_blank">change note</a> See the <a href="https://github.com/angular/in-memory-web-api/blob/master/CHANGELOG.md#0113-2016-10-20" target="_blank">change note</a>
in the `in-memory-web-api` repo. in the `in-memory-web-api` repo.
## "Router" _preload_ syntax and _:enter_/_:leave_ animations (2016-10-19) ## "Router" _preload_ syntax and _:enter_/_:leave_ animations (2016-10-19)
The router can lazily _preload_ modules _after_ the app starts and The router can lazily _preload_ modules _after_ the app starts and
_before_ the user navigates to them for improved perceived performance. _before_ the user navigates to them for improved perceived performance.
New `:enter` and `:leave` aliases make animation more natural. New `:enter` and `:leave` aliases make animation more natural.
## Sync with Angular v.2.1.0 (2016-10-12) ## Sync with Angular v.2.1.0 (2016-10-12)
Docs and code samples updated and tested with Angular v.2.1.0. Docs and code samples updated and tested with Angular v.2.1.0.
## NEW "Ahead of time (AOT) Compilation" cookbook (2016-10-11) ## NEW "Ahead of time (AOT) Compilation" cookbook (2016-10-11)
The NEW [Ahead of time (AOT) Compilation](../cookbook/aot-compiler.html) cookbook The NEW [Ahead of time (AOT) Compilation](../cookbook/aot-compiler.html) cookbook
explains what AOT compilation is and why you'd want it. explains what AOT compilation is and why you'd want it.
It demonstrates the basics with a QuickStart app It demonstrates the basics with a QuickStart app
followed by the more advanced considerations of compiling and bundling the Tour of Heroes. followed by the more advanced considerations of compiling and bundling the Tour of Heroes.
## Sync with Angular v.2.0.2 (2016-10-6) ## Sync with Angular v.2.0.2 (2016-10-6)
Docs and code samples updated and tested with Angular v.2.0.2. Docs and code samples updated and tested with Angular v.2.0.2.
## "Routing and Navigation" guide with the _Router Module_ (2016-10-5) ## "Routing and Navigation" guide with the _Router Module_ (2016-10-5)
The [Routing and Navigation](router.html) guide now locates route configuration The [Routing and Navigation](router.html) guide now locates route configuration
in a _Routing Module_. in a _Routing Module_.
The _Routing Module_ replaces the previous _routing object_ involving the `ModuleWithProviders`. The _Routing Module_ replaces the previous _routing object_ involving the `ModuleWithProviders`.

View File

@ -126,6 +126,7 @@ a(id='loading-styles')
## Loading styles into components ## Loading styles into components
There are several ways to add styles to a component: There are several ways to add styles to a component:
* By setting `styles` or `styleUrls` metadata. * By setting `styles` or `styleUrls` metadata.
* Inline in the template HTML. * Inline in the template HTML.
* With CSS imports. * With CSS imports.
@ -215,9 +216,11 @@ a#view-encapsulation
on the [MDN](https://developer.mozilla.org) site) on the [MDN](https://developer.mozilla.org) site)
to attach a shadow DOM to the component's host element, and then puts the component 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. 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 * `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. (and renaming) the CSS code to effectively scope the CSS to the component's view.
For details, see [Appendix 1](#inspect-generated-css). For details, see [Appendix 1](#inspect-generated-css).
* `None` means that Angular does no view encapsulation. * `None` means that Angular does no view encapsulation.
Angular adds the CSS to the global styles. Angular adds the CSS to the global styles.
The scoping rules, isolations, and protections discussed earlier don't apply. The scoping rules, isolations, and protections discussed earlier don't apply.
@ -256,6 +259,7 @@ code-example(format="").
:marked :marked
There are two kinds of generated attributes: There are two kinds of generated attributes:
* An element that would be a shadow DOM host in native encapsulation has a * 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. generated `_nghost` attribute. This is typically the case for component host elements.
* An element within a component's view has a `_ngcontent` attribute * An element within a component's view has a `_ngcontent` attribute

View File

@ -12,32 +12,38 @@ block includes
:marked :marked
# Contents # Contents
- [Why dependency injection?](#why-di) * [Why dependency injection?](#why-di)
- [Angular dependency injection](#angular-dependency-injection) * [Angular dependency injection](#angular-dependency-injection)
- [Configuring the injector](#injector-config)
- [Registering providers in an `NgModule`](#register-providers-ngmodule) * [Configuring the injector](#injector-config)
- [Registering providers in a component](#register-providers-component) * [Registering providers in an `NgModule`](#register-providers-ngmodule)
- [When to use `NgModule` versus an application component](#ngmodule-vs-comp) * [Registering providers in a component](#register-providers-component)
- [Preparing the `HeroListComponent` for injection](#prep-for-injection) * [When to use `NgModule` versus an application component](#ngmodule-vs-comp)
- [Implicit injector creation](#di-metadata) * [Preparing the `HeroListComponent` for injection](#prep-for-injection)
- [Singleton services](#singleton-services) * [Implicit injector creation](#di-metadata)
- [Testing the component](#testing-the-component) * [Singleton services](#singleton-services)
- [When the service needs a service](#service-needs-service) * [Testing the component](#testing-the-component)
- [Why `@Injectable()`?](#injectable) * [When the service needs a service](#service-needs-service)
- [Creating and registering a logger service](#logger-service) * [Why `@Injectable()`?](#injectable)
- [Injector providers](#injector-providers)
- [The `Provider` class and `provide` object literal](#provide) * [Creating and registering a logger service](#logger-service)
- [Alternative class providers](#class-provider) * [Injector providers](#injector-providers)
- [Class provider with dependencies](#class-provider-dependencies)
- [Aliased class providers](#aliased-class-providers) * [The `Provider` class and `provide` object literal](#provide)
- [Value providers](#value-provider) * [Alternative class providers](#class-provider)
- [Factory providers](#factory-provider) * [Class provider with dependencies](#class-provider-dependencies)
- [Dependency injection tokens](#dependency-injection-tokens) * [Aliased class providers](#aliased-class-providers)
- [Non-class dependencies](#non-class-dependencies) * [Value providers](#value-provider)
- [`OpaqueToken`](#opaquetoken) * [Factory providers](#factory-provider)
- [Optional dependencies](#optional)
- [Summary](#summary) * [Dependency injection tokens](#dependency-injection-tokens)
- [Appendix: Working with injectors directly](#explicit-injector)
* [Non-class dependencies](#non-class-dependencies)
* [`OpaqueToken`](#opaquetoken)
* [Optional dependencies](#optional)
* [Summary](#summary)
* [Appendix: Working with injectors directly](#explicit-injector)
Run the <live-example></live-example>. Run the <live-example></live-example>.
@ -493,6 +499,7 @@ a#injectable
## Creating and registering a logger service ## Creating and registering a logger service
Inject a logger into `HeroService` in two steps: Inject a logger into `HeroService` in two steps:
1. Create the logger service. 1. Create the logger service.
1. Register it with the application. 1. Register it with the application.

View File

@ -196,14 +196,14 @@ a#optimize
If it _does_ matter, there are tools and techniques to reduce the number of requests and the size of responses. If it _does_ matter, there are tools and techniques to reduce the number of requests and the size of responses.
- Ahead-of-Time (AOT) Compilation: pre-compiles Angular component templates. * Ahead-of-Time (AOT) Compilation: pre-compiles Angular component templates.
- Bundling: concatenates modules into a single file (bundle). * Bundling: concatenates modules into a single file (bundle).
- Inlining: pulls template html and css into the components. * Inlining: pulls template html and css into the components.
- Minification: removes excess whitespace, comments, and optional tokens. * Minification: removes excess whitespace, comments, and optional tokens.
- Uglification: rewrites code to use short, cryptic variable and function names. * Uglification: rewrites code to use short, cryptic variable and function names.
- Dead code elimination: removes unreferenced modules and unused code. * Dead code elimination: removes unreferenced modules and unused code.
- Pruned libraries: drop unused libraries and pare others down to the features you need. * Pruned libraries: drop unused libraries and pare others down to the features you need.
- Performance measurement: focus on optimizations that make a measurable difference. * Performance measurement: focus on optimizations that make a measurable difference.
Each tool does something different. Each tool does something different.
They work best in combination and are mutually reinforcing. They work best in combination and are mutually reinforcing.
@ -220,6 +220,7 @@ a#aot
during the build process. during the build process.
Apps compiled with AOT launch faster for several reasons. Apps compiled with AOT launch faster for several reasons.
* Application components execute immediately, without client-side compilation. * Application components execute immediately, without client-side compilation.
* Templates are embedded as code within their components so there is no client-side request for template files. * Templates are embedded as code within their components so there is no client-side request for template files.
* You don't download the Angular compiler, which is pretty big on its own. * You don't download the Angular compiler, which is pretty big on its own.
@ -414,10 +415,10 @@ a#deep-link
#### Development servers #### Development servers
- [Lite-Server](https://github.com/johnpapa/lite-server): the default dev server installed with the * [Lite-Server](https://github.com/johnpapa/lite-server): the default dev server installed with the
[Quickstart repo](https://github.com/angular/quickstart) is pre-configured to fallback to `index.html`. [Quickstart repo](https://github.com/angular/quickstart) is pre-configured to fallback to `index.html`.
- [Webpack-Dev-Server](https://github.com/webpack/webpack-dev-server): setup the * [Webpack-Dev-Server](https://github.com/webpack/webpack-dev-server): setup the
`historyApiFallback` entry in the dev server options as follows: `historyApiFallback` entry in the dev server options as follows:
code-example(). code-example().
@ -429,10 +430,11 @@ code-example().
:marked :marked
#### Production servers #### Production servers
- [Apache](https://httpd.apache.org/): add a * [Apache](https://httpd.apache.org/): add a
[rewrite rule](http://httpd.apache.org/docs/current/mod/mod_rewrite.html) [rewrite rule](http://httpd.apache.org/docs/current/mod/mod_rewrite.html)
to the `.htaccess` file as show to the `.htaccess` file as show
[here](https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/): [here](https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/):
code-example(format="."). code-example(format=".").
RewriteEngine On RewriteEngine On
# If an existing asset or directory is requested go to it as it is # If an existing asset or directory is requested go to it as it is
@ -444,7 +446,7 @@ code-example(format=".").
RewriteRule ^ /index.html RewriteRule ^ /index.html
:marked :marked
- [NGinx](http://nginx.org/): use `try_files`, as described in * [NGinx](http://nginx.org/): use `try_files`, as described in
[Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps), [Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps),
modified to serve `index.html`: modified to serve `index.html`:
@ -452,7 +454,7 @@ code-example(format=".").
try_files $uri $uri/ /index.html; try_files $uri $uri/ /index.html;
:marked :marked
- [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown * [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown
[here](http://stackoverflow.com/a/26152011/2116927): [here](http://stackoverflow.com/a/26152011/2116927):
code-example(format="." escape="html"). code-example(format="." escape="html").
<system.webServer> <system.webServer>
@ -471,7 +473,7 @@ code-example(format="." escape="html").
</system.webServer> </system.webServer>
:marked :marked
- [GitHub Pages](https://pages.github.com/): you can't * [GitHub Pages](https://pages.github.com/): you can't
[directly configure](https://github.com/isaacs/github/issues/408) [directly configure](https://github.com/isaacs/github/issues/408)
the GitHub Pages server, but you can add a 404 page. the GitHub Pages server, but you can add a 404 page.
Copy `index.html` into `404.html`. Copy `index.html` into `404.html`.
@ -481,7 +483,7 @@ code-example(format="." escape="html").
and to and to
[create a `.nojekyll` file](https://www.bennadel.com/blog/3181-including-node-modules-and-vendors-folders-in-your-github-pages-site.htm) [create a `.nojekyll` file](https://www.bennadel.com/blog/3181-including-node-modules-and-vendors-folders-in-your-github-pages-site.htm)
- [Firebase hosting](https://firebase.google.com/docs/hosting/): add a * [Firebase hosting](https://firebase.google.com/docs/hosting/): add a
[rewrite rule](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites). [rewrite rule](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites).
code-example(format="."). code-example(format=".").

View File

@ -188,6 +188,7 @@ figure.image-display
:marked :marked
That brief syntax does a lot: That brief syntax does a lot:
* Declares a constructor parameter and its type. * Declares a constructor parameter and its type.
* Declares a public property of the same name. * Declares a public property of the same name.
* Initializes that property with the corresponding argument when creating an instance of the class. * Initializes that property with the corresponding argument when creating an instance of the class.
@ -252,10 +253,11 @@ figure.image-display
:marked :marked
## Summary ## Summary
Now you know how to use: Now you know how to use:
- **Interpolation** with double curly braces to display a component property.
- **ngFor** to display an array of items. * **Interpolation** with double curly braces to display a component property.
- A TypeScript class to shape the **model data** for your component and display properties of that model. * **ngFor** to display an array of items.
- **ngIf** to conditionally display a chunk of HTML based on a boolean expression. * A TypeScript class to shape the **model data** for your component and display properties of that model.
* **ngIf** to conditionally display a chunk of HTML based on a boolean expression.
Here's the final code: Here's the final code:

View File

@ -14,12 +14,12 @@ include ../_util-fns
This page shows you how to build a simple form from scratch. Along the way you'll learn how to: This page shows you how to build a simple form from scratch. Along the way you'll learn how to:
- Build an Angular form with a component and template. * Build an Angular form with a component and template.
- Use `ngModel` to create two-way data bindings for reading and writing input-control values. * Use `ngModel` to create two-way data bindings for reading and writing input-control values.
- Track state changes and the validity of form controls. * Track state changes and the validity of form controls.
- Provide visual feedback using special CSS classes that track the state of the 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. * Display validation errors to users and enable/disable form controls.
- Share information across HTML elements using template reference variables. * Share information across HTML elements using template reference variables.
You can run the <live-example></live-example> in Plunker and download the code from there. You can run the <live-example></live-example> in Plunker and download the code from there.
@ -128,16 +128,18 @@ figure.image-display
Understanding this component requires only the Angular concepts covered in previous pages. Understanding this component requires only the Angular concepts covered in previous pages.
- The code imports the Angular core library and the `Hero` model you just created. * 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 `@Component` selector value of "hero-form" means you can drop this form in a parent template with a `<hero-form>` tag.
- The `templateUrl` property points to a separate file for the template HTML. * The `templateUrl` property points to a separate file for the template HTML.
- You defined dummy data for `model` and `powers`, as befits a demo. * 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 Down the road, you can inject a data service to get and save real data
or perhaps expose these properties as inputs and outputs or perhaps expose these properties as inputs and outputs
(see [Input and output properties](./template-syntax.html#inputs-outputs) on the (see [Input and output properties](./template-syntax.html#inputs-outputs) on the
[Template Syntax](./template-syntax.html) page) for binding to a [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. 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.
* 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. 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 the separate template file?
@ -333,9 +335,9 @@ figure.image-display
.l-sub-section .l-sub-section
:marked :marked
- Each input element has an `id` property that is used by the `label` element's `for` attribute * 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. 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. * Each input element has a `name` property that is required by Angular forms to register the control with the form.
:marked :marked
If you run the app now and change 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:
@ -445,8 +447,9 @@ figure.image-display
:marked :marked
To achieve this effect, extend the `<input>` tag with the following: 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. * 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 an error message added to the _name_ input box: Here's an example of an error message added to the _name_ input box:
@ -639,15 +642,15 @@ figure.image-display
The Angular form discussed in this page 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: framework features to provide support for data modification, validation, and more:
- An Angular HTML form template. * An Angular HTML form template.
- A form component class with a `@Component` decorator. * A form component class with a `@Component` decorator.
- Handling form submission by binding to the `NgForm.ngSubmit` event property. * 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. * `[(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. * 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. * Custom CSS classes that provide visual feedback to users about invalid controls.
The final project folder structure should look like this: The final project folder structure should look like this:

View File

@ -18,6 +18,7 @@ figure
:marked :marked
## Contents ## Contents
* [Component lifecycle hooks overview](#hooks-overview) * [Component lifecycle hooks overview](#hooks-overview)
* [Lifecycle sequence](#hooks-purpose-timing) * [Lifecycle sequence](#hooks-purpose-timing)
* [Interfaces are optional (technically)](#interface-optional) * [Interfaces are optional (technically)](#interface-optional)
@ -25,13 +26,18 @@ figure
* [Lifecycle examples](#the-sample) * [Lifecycle examples](#the-sample)
* [Peek-a-boo: all hooks](#peek-a-boo) * [Peek-a-boo: all hooks](#peek-a-boo)
* [Spying OnInit and OnDestroy](#spy) * [Spying OnInit and OnDestroy](#spy)
* [OnInit](#oninit) * [OnInit](#oninit)
* [OnDestroy](#ondestroy) * [OnDestroy](#ondestroy)
* [OnChanges](#onchanges) * [OnChanges](#onchanges)
* [DoCheck](#docheck) * [DoCheck](#docheck)
* [AfterView](#afterview) * [AfterView](#afterview)
* [Abide by the unidirectional data flow rule](#wait-a-tick) * [Abide by the unidirectional data flow rule](#wait-a-tick)
* [AfterContent](#aftercontent) * [AfterContent](#aftercontent)
* [Content projection](#content-projection) * [Content projection](#content-projection)
* [AfterContent hooks](#aftercontent-hooks) * [AfterContent hooks](#aftercontent-hooks)
* [No unidirectional flow worries with _AfterContent_](#no-unidirectional-flow-worries) * [No unidirectional flow worries with _AfterContent_](#no-unidirectional-flow-worries)
@ -331,6 +337,7 @@ a#oninit
### _OnInit()_ ### _OnInit()_
Use `ngOnInit()` for two main reasons: Use `ngOnInit()` for two main reasons:
1. To perform complex initializations shortly after construction. 1. To perform complex initializations shortly after construction.
1. To set up the component after Angular sets the input properties. 1. To set up the component after Angular sets the input properties.
@ -522,11 +529,14 @@ figure.image-display
.l-sub-section .l-sub-section
:marked :marked
The telltale signs of *content projection* are twofold: The telltale signs of *content projection* are twofold:
- HTML between component element tags.
- The presence of `<ng-content>` tags in the component's template. * HTML between component element tags.
* The presence of `<ng-content>` tags in the component's template.
a#aftercontent-hooks a#aftercontent-hooks
:marked :marked
### AfterContent hooks ### AfterContent hooks
*AfterContent* hooks are similar to the *AfterView* hooks. *AfterContent* hooks are similar to the *AfterView* hooks.
The key difference is in the child component. The key difference is in the child component.

View File

@ -21,13 +21,13 @@ style.
### Table of contents ### Table of contents
- [Introduction](#introduction) * [Introduction](#introduction)
- [The problem](#problem) * [The problem](#problem)
- [Troublesome CSS](#CSS) * [Troublesome CSS](#CSS)
- [Restrictive layout](#restrictive-layout) * [Restrictive layout](#restrictive-layout)
- [&lt;ng-container&gt; is excluded from DOM](#excluded) * [&lt;ng-container&gt; is excluded from DOM](#excluded)
- [&lt;ng-container&gt; is not &lt;ng-content&gt;](#ng-content) * [&lt;ng-container&gt; is not &lt;ng-content&gt;](#ng-content)
- [Summary](#summary) * [Summary](#summary)
Try the <live-example></live-example>. Try the <live-example></live-example>.

View File

@ -25,9 +25,11 @@ block includes
## Table of Contents ## Table of Contents
<!-- CF: The titling for tables of contents in the advanced chapters is inconsistent: <!-- CF: The titling for tables of contents in the advanced chapters is inconsistent:
- some are titled "Contents" while others are titled "Table of Contents" (should probably be sentence case as it's an H2
- some headings are H2, some are H3 * some are titled "Contents" while others are titled "Table of Contents" (should probably be sentence case as it's an H2
- some pages don't have tables of contents * some headings are H2, some are H3
* some pages don't have tables of contents
I didn't make changes here as I'm not sure what the correct style is. I didn't make changes here as I'm not sure what the correct style is.
--> -->
@ -351,6 +353,7 @@ a#imports
`ngModel` is the selector for the `NgModel` directive. `ngModel` is the selector for the `NgModel` directive.
Although `NgModel` is an Angular directive, the _Angular compiler_ won't recognize it for the following reasons: Although `NgModel` is an Angular directive, the _Angular compiler_ won't recognize it for the following reasons:
* `AppModule` doesn't declare `NgModel`. * `AppModule` doesn't declare `NgModel`.
* `NgModel` wasn't imported via `BrowserModule`. * `NgModel` wasn't imported via `BrowserModule`.
@ -619,9 +622,11 @@ a#feature-modules
### Improvements ### Improvements
:marked :marked
There's a lot to like in the revised `AppModule`. There's a lot to like in the revised `AppModule`.
* It does not change as the _Contact_ domain grows. * It does not change as the _Contact_ domain grows.
* It only changes when you add new modules. * It only changes when you add new modules.
* It's simpler: * It's simpler:
* Fewer import statements. * Fewer import statements.
* No `FormsModule` import. * No `FormsModule` import.
* No contact-specific declarations. * No contact-specific declarations.
@ -818,6 +823,7 @@ a#shared-module
and share them with the modules that need them. and share them with the modules that need them.
1. Create an `src/app/shared` folder. 1. Create an `src/app/shared` folder.
* Move the `AwesomePipe` and `HighlightDirective` from `src/app/contact` to `src/app/shared`. * Move the `AwesomePipe` and `HighlightDirective` from `src/app/contact` to `src/app/shared`.
* Delete the `HighlightDirective` classes from `src/app/` and `src/app/hero`. * Delete the `HighlightDirective` classes from `src/app/` and `src/app/hero`.
* Create a `SharedModule` class to own the shared material. * Create a `SharedModule` class to own the shared material.
@ -827,6 +833,7 @@ a#shared-module
+makeExample('ngmodule/ts/src/app/shared/shared.module.ts', '', 'src/app/src/app/shared/shared.module.ts') +makeExample('ngmodule/ts/src/app/shared/shared.module.ts', '', 'src/app/src/app/shared/shared.module.ts')
:marked :marked
Note the following: Note the following:
* It imports the `CommonModule` because its component needs common directives. * It imports the `CommonModule` because its component needs common directives.
* It declares and exports the utility pipe, directive, and component classes as expected. * It declares and exports the utility pipe, directive, and component classes as expected.
* It re-exports the `CommonModule` and `FormsModule` * It re-exports the `CommonModule` and `FormsModule`
@ -954,6 +961,7 @@ a#core-module
:marked :marked
`AppModule` now has the following qualities: `AppModule` now has the following qualities:
* A little smaller because many `src/app/root` classes have moved to other modules. * A little smaller because many `src/app/root` classes have moved to other modules.
* Stable because you'll add future components and providers to other modules, not this one. * Stable because you'll add future components and providers to other modules, not this one.
* Delegated to imported modules rather than doing work. * Delegated to imported modules rather than doing work.
@ -970,6 +978,7 @@ a#core-module
:marked :marked
Notice the following: Notice the following:
* The `AwesomePipe` and `HighlightDirective` are gone. * The `AwesomePipe` and `HighlightDirective` are gone.
* The imports include `SharedModule` instead of `CommonModule` and `FormsModule`. * The imports include `SharedModule` instead of `CommonModule` and `FormsModule`.
* The new version is leaner and cleaner. * The new version is leaner and cleaner.
@ -987,6 +996,7 @@ a#core-for-root
It takes a service configuration object and returns a It takes a service configuration object and returns a
[ModuleWithProviders](../api/core/index/ModuleWithProviders-interface.html), which is [ModuleWithProviders](../api/core/index/ModuleWithProviders-interface.html), which is
a simple object with the following properties: a simple object with the following properties:
* `ngModule`: the `CoreModule` class * `ngModule`: the `CoreModule` class
* `providers`: the configured providers * `providers`: the configured providers

View File

@ -101,7 +101,6 @@ block includes
figure.image-display figure.image-display
img(src='/resources/images/devguide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle") img(src='/resources/images/devguide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle")
:marked
.l-sub-section .l-sub-section
:marked :marked
@ -386,6 +385,7 @@ figure.image-display
:marked :marked
A breakpoint on the pipe's request for data shows the following: A breakpoint on the pipe's request for data shows the following:
* Each binding gets its own pipe instance. * Each binding gets its own pipe instance.
* Each pipe instance caches its own URL and data. * Each pipe instance caches its own URL and data.
* Each pipe instance only calls the server once. * Each pipe instance only calls the server once.

View File

@ -8,23 +8,23 @@ a#toc
:marked :marked
## Contents ## Contents
- [Introduction to reactive forms](#intro) * [Introduction to reactive forms](#intro)
- [Setup](#setup) * [Setup](#setup)
- [Create a data model](#data-model) * [Create a data model](#data-model)
- [Create a _reactive forms_ component](#create-component) * [Create a _reactive forms_ component](#create-component)
- [Create its template file](#create-template) * [Create its template file](#create-template)
- [Import the _ReactiveFormsModule_](#import) * [Import the _ReactiveFormsModule_](#import)
- [Display the _HeroDetailComponent_](#update) * [Display the _HeroDetailComponent_](#update)
- [Add a FormGroup](#formgroup) * [Add a FormGroup](#formgroup)
- [Taking a look at the form model](#json) * [Taking a look at the form model](#json)
- [Introduction to _FormBuilder_](#formbuilder) * [Introduction to _FormBuilder_](#formbuilder)
- [Validators.required](#validators) * [Validators.required](#validators)
- [Nested FormGroups](#grouping) * [Nested FormGroups](#grouping)
- [Inspect _FormControl_ properties](#properties) * [Inspect _FormControl_ properties](#properties)
- [Set form model data using _setValue_ and _patchValue_](#set-data) * [Set form model data using _setValue_ and _patchValue_](#set-data)
- [Use _FormArray_ to present an array of _FormGroups_](#form-array) * [Use _FormArray_ to present an array of _FormGroups_](#form-array)
- [Observe control changes](#observe-control) * [Observe control changes](#observe-control)
- [Save form data](#save) * [Save form data](#save)
Try the <live-example plnkr="final" title="Reactive Forms (final) in Plunker">Reactive Forms live-example</live-example>. Try the <live-example plnkr="final" title="Reactive Forms (final) in Plunker">Reactive Forms live-example</live-example>.
@ -229,6 +229,7 @@ a#import
In this sample, you declare the `HeroDetailComponent` in the `AppModule`. In this sample, you declare the `HeroDetailComponent` in the `AppModule`.
Therefore, do the following three things in `app.module.ts`: Therefore, do the following three things in `app.module.ts`:
1. Use a JavaScript `import` statement to access 1. Use a JavaScript `import` statement to access
the `ReactiveFormsModule` and the `HeroDetailComponent`. the `ReactiveFormsModule` and the `HeroDetailComponent`.
1. Add `ReactiveFormsModule` to the `AppModule`'s `imports` list. 1. Add `ReactiveFormsModule` to the `AppModule`'s `imports` list.
@ -1017,14 +1018,14 @@ figure.image-display
This page covered: This page covered:
- How to create a reactive form component and its corresponding template. * How to create a reactive form component and its corresponding template.
- How to use `FormBuilder` to simplify coding a reactive form. * How to use `FormBuilder` to simplify coding a reactive form.
- Grouping `FormControls`. * Grouping `FormControls`.
- Inspecting `FormControl` properties. * Inspecting `FormControl` properties.
- Setting data with `patchValue` and `setValue`. * Setting data with `patchValue` and `setValue`.
- Adding groups dynamically with `FormArray`. * Adding groups dynamically with `FormArray`.
- Observing changes to the value of a `FormControl`. * Observing changes to the value of a `FormControl`.
- Saving form changes. * Saving form changes.
a#source-code a#source-code
:marked :marked

View File

@ -33,84 +33,100 @@ include ../../../_includes/_see-addr-bar
# Contents # Contents
* [The Basics](#basics) * [The Basics](#basics)
- [`<base href>`](#basics-base-href)
- [Router imports](#basics-router-imports) * [`<base href>`](#basics-base-href)
- [Configuration](#basics-config) * [Router imports](#basics-router-imports)
- [Router outlet](#basics-router-outlet) * [Configuration](#basics-config)
- [Router links](#basics-router-links) * [Router outlet](#basics-router-outlet)
- [Router state](#basics-router-state) * [Router links](#basics-router-links)
- [Summary](#basics-summary) * [Router state](#basics-router-state)
* [Summary](#basics-summary)
* [The sample application](#sample-app-intro) * [The sample application](#sample-app-intro)
* [Milestone 1: Getting started with the router](#getting-started) * [Milestone 1: Getting started with the router](#getting-started)
- [Setting the base href](#base-href)
- [Importing from the router library](#import) * [Setting the base href](#base-href)
- [Define routes](#route-config) * [Importing from the router library](#import)
- [The `AppComponent` shell](#shell) * [Define routes](#route-config)
- [RouterOutlet](#router-outlet) * [The `AppComponent` shell](#shell)
- [`RouterLink binding`](#router-link) * [RouterOutlet](#router-outlet)
- [`RouterLinkActive` binding](#router-link-active) * [`RouterLink binding`](#router-link)
- [Wildcard route](#wildcard) * [`RouterLinkActive` binding](#router-link-active)
- [The default route to heroes](#default-route) * [Wildcard route](#wildcard)
* [The default route to heroes](#default-route)
* [Milestone 2: Routing module](#routing-module) * [Milestone 2: Routing module](#routing-module)
- [Refactor the routing configuration into a routing module](#routing-refactor)
- [Do you need a Routing Module?](#why-routing-module) * [Refactor the routing configuration into a routing module](#routing-refactor)
* [Do you need a Routing Module?](#why-routing-module)
* [Milestone 3: Heroes feature](#heroes-feature) * [Milestone 3: Heroes feature](#heroes-feature)
- [Add heroes functionality](#heroes-functionality)
- [Hero feature routing requirements](#hero-routing-requirements) * [Add heroes functionality](#heroes-functionality)
- [Hero feature route configuration](#hero-routing-module) * [Hero feature routing requirements](#hero-routing-requirements)
- [Add the routing module to the _HeroesModule_](#adding-routing-module) * [Hero feature route configuration](#hero-routing-module)
- [Remove duplicate hero routes](#remove-duplicate-hero-routes) * [Add the routing module to the _HeroesModule_](#adding-routing-module)
- [Import hero module into AppModule](#merge-hero-routes) * [Remove duplicate hero routes](#remove-duplicate-hero-routes)
- [Module import order matters](#routing-module-order) * [Import hero module into AppModule](#merge-hero-routes)
- [Route Definition with a parameter](#route-def-with-parameter) * [Module import order matters](#routing-module-order)
- [Navigate to hero detail imperatively](#navigate) * [Route Definition with a parameter](#route-def-with-parameter)
- [Setting the route parameters in the list view](#route-parameters) * [Navigate to hero detail imperatively](#navigate)
- [ActivatedRoute: the one-stop-shop for route information](#activated-route) * [Setting the route parameters in the list view](#route-parameters)
- [Observable params and component reuse](#reuse) * [ActivatedRoute: the one-stop-shop for route information](#activated-route)
- [Snapshot: the _no-observable_ alternative](#snapshot) * [Observable params and component reuse](#reuse)
- [Navigating back to the list component](#nav-to-list) * [Snapshot: the _no-observable_ alternative](#snapshot)
- [Route Parameters: Required or optional?](#optional-route-parameters) * [Navigating back to the list component](#nav-to-list)
- [Heroes list: optionally selecting a hero](#optionally-selecting) * [Route Parameters: Required or optional?](#optional-route-parameters)
- [Route parameters in the *ActivatedRoute* service](#route-parameters-activated-route) * [Heroes list: optionally selecting a hero](#optionally-selecting)
- [Adding animations to the routed component](#route-animation) * [Route parameters in the *ActivatedRoute* service](#route-parameters-activated-route)
- [Milestone 3 wrap up](#milestone-3-wrap-up) * [Adding animations to the routed component](#route-animation)
* [Milestone 3 wrap up](#milestone-3-wrap-up)
* [Milestone 4: Crisis center feature](#milestone-4) * [Milestone 4: Crisis center feature](#milestone-4)
- [A crisis center with child routes](#crisis-child-routes)
- [Child routing component](#child-routing-component) * [A crisis center with child routes](#crisis-child-routes)
- [Child route configuration](#child-route-config) * [Child routing component](#child-routing-component)
- [Import crisis center module into the _AppModule_ routes](#import-crisis-module) * [Child route configuration](#child-route-config)
- [Relative navigation](#relative-navigation) * [Import crisis center module into the _AppModule_ routes](#import-crisis-module)
- [Navigate to crisis detail with a relative URL](#nav-to-crisis) * [Relative navigation](#relative-navigation)
- [Displaying multiple routes in named outlets](#named-outlets) * [Navigate to crisis detail with a relative URL](#nav-to-crisis)
- [Secondary routes](#secondary-routes) * [Displaying multiple routes in named outlets](#named-outlets)
- [Add a secondary route](#add-secondary-route) * [Secondary routes](#secondary-routes)
- [Secondary route navigation: merging routes during navigation](#secondary-route-navigation) * [Add a secondary route](#add-secondary-route)
- [Clearing secondary routes](#clear-secondary-routes) * [Secondary route navigation: merging routes during navigation](#secondary-route-navigation)
* [Clearing secondary routes](#clear-secondary-routes)
* [Milestone 5: Route guards](#guards) * [Milestone 5: Route guards](#guards)
- [`CanActivate`: requiring authentication](#can-activate-guard)
- [Component-less route: grouping routes without a component](#component-less-route) * [`CanActivate`: requiring authentication](#can-activate-guard)
- [Guard the admin feature](#guard-admin-feature) * [Component-less route: grouping routes without a component](#component-less-route)
- [Teach *AuthGuard* to authenticate](#teach-auth) * [Guard the admin feature](#guard-admin-feature)
- [Add the login component](#add-login-component) * [Teach *AuthGuard* to authenticate](#teach-auth)
- [`CanActivateChild`: guarding child routes](#can-activate-child-guard) * [Add the login component](#add-login-component)
- [`CanDeactivate`: handling unsaved changes](#can-deactivate-guard) * [`CanActivateChild`: guarding child routes](#can-activate-child-guard)
- [Cancel and save](#cancel-save) * [`CanDeactivate`: handling unsaved changes](#can-deactivate-guard)
- [`Resolve`: pre-fetching component data](#resolve-guard) * [Cancel and save](#cancel-save)
- [Fetch data before navigating](#fetch-before-navigating ) * [`Resolve`: pre-fetching component data](#resolve-guard)
- [Query parameters and fragments](#query-parameters) * [Fetch data before navigating](#fetch-before-navigating )
* [Query parameters and fragments](#query-parameters)
* [Milestone 6: Asynchronous routing](#asynchronous-routing) * [Milestone 6: Asynchronous routing](#asynchronous-routing)
- [Lazy loading route configuration](#lazy-loading-route-config)
- [CanLoad Guard: guarding unauthorized loading of feature modules](#can-load-guard) * [Lazy loading route configuration](#lazy-loading-route-config)
- [Preloading: background loading of feature areas](#preloading) * [CanLoad Guard: guarding unauthorized loading of feature modules](#can-load-guard)
- [How preloading works](#how-preloading) * [Preloading: background loading of feature areas](#preloading)
- [Lazy load the crisis center](#lazy-load-crisis-center) * [How preloading works](#how-preloading)
- [_CanLoad_ blocks preload](#preload-canload) * [Lazy load the crisis center](#lazy-load-crisis-center)
- [Custom Preloading Strategy](#custom-preloading) * [_CanLoad_ blocks preload](#preload-canload)
- [Inspect the router's configuration](#inspect-config) * [Custom Preloading Strategy](#custom-preloading)
- [Wrap up and final app](#final-app) * [Inspect the router's configuration](#inspect-config)
* [Wrap up and final app](#final-app)
* [Appendices](#appendices) * [Appendices](#appendices)
- [Appendix: link parameters array](#link-parameters-array)
- [Appendix: *LocationStrategy* and browser URL styles](#location-strategy) * [Appendix: link parameters array](#link-parameters-array)
* [Appendix: *LocationStrategy* and browser URL styles](#location-strategy)
@ -491,10 +507,10 @@ a#route-config
In simpler terms, you might say this of the first route: In simpler terms, you might say this of the first route:
- When the browser's location URL changes to match the path segment `/crisis-center`, then * When the browser's location URL changes to match the path segment `/crisis-center`, then
the router activates an instance of the `CrisisListComponent` and displays its view. the router activates an instance of the `CrisisListComponent` and displays its view.
- When the application requests navigation to the path `/crisis-center`, the router * When the application requests navigation to the path `/crisis-center`, the router
activates an instance of `CrisisListComponent`, displays its view, and updates the activates an instance of `CrisisListComponent`, displays its view, and updates the
browser's address location and history with the URL for that path. browser's address location and history with the URL for that path.
@ -758,6 +774,7 @@ a#redirect
We recommend moving the routing information into a special-purpose module called a *Routing Module*. We recommend moving the routing information into a special-purpose module called a *Routing Module*.
The **Routing Module** has several characteristics: The **Routing Module** has several characteristics:
* Separates routing concerns from other application concerns. * Separates routing concerns from other application concerns.
* Provides a module to replace or remove when testing the application. * Provides a module to replace or remove when testing the application.
* Provides a well-known location for routing service providers including guards and resolvers. * Provides a well-known location for routing service providers including guards and resolvers.
@ -856,19 +873,21 @@ a#heroes-functionality
Follow these steps: Follow these steps:
- Create the `src/app/heroes` folder; you'll be adding files implementing *hero management* there. * Create the `src/app/heroes` folder; you'll be adding files implementing *hero management* there.
- Delete the placeholder `hero-list.component.ts` that's in the `app` folder. * Delete the placeholder `hero-list.component.ts` that's in the `app` folder.
- Create a new `hero-list.component.ts` under `src/app/heroes`. * Create a new `hero-list.component.ts` under `src/app/heroes`.
- Copy into it the contents of the `app.component.ts` from * Copy into it the contents of the `app.component.ts` from
the <live-example name="toh-4" title="Tour of Heroes: Services example code">"Services" tutorial</live-example>. the <live-example name="toh-4" title="Tour of Heroes: Services example code">"Services" tutorial</live-example>.
- Make a few minor but necessary changes: * Make a few minor but necessary changes:
- Delete the `selector` (routed components don't need them).
- Delete the `<h1>`. * Delete the `selector` (routed components don't need them).
- Relabel the `<h2>` to `<h2>HEROES</h2>`. * Delete the `<h1>`.
- Delete the `<hero-detail>` at the bottom of the template. * Relabel the `<h2>` to `<h2>HEROES</h2>`.
- Rename the `AppComponent` class to `HeroListComponent`. * Delete the `<hero-detail>` at the bottom of the template.
- Copy the `hero-detail.component.ts` and the `hero.service.ts` files into the `heroes` subfolder. * Rename the `AppComponent` class to `HeroListComponent`.
- Create a (pre-routing) `heroes.module.ts` in the heroes folder that looks like this:
* Copy the `hero-detail.component.ts` and the `hero.service.ts` files into the `heroes` subfolder.
* Create a (pre-routing) `heroes.module.ts` in the heroes folder that looks like this:
+makeExample('src/app/heroes/heroes.module.ts', 'v1','src/app/heroes/heroes.module.ts (pre-routing)') +makeExample('src/app/heroes/heroes.module.ts', 'v1','src/app/heroes/heroes.module.ts (pre-routing)')
@ -1542,10 +1561,10 @@ a#milestone-4
Begin by imitating the heroes feature: Begin by imitating the heroes feature:
- Delete the placeholder crisis center file. * Delete the placeholder crisis center file.
- Create an `app/crisis-center` folder. * Create an `app/crisis-center` folder.
- Copy the files from `app/heroes` into the new crisis center folder. * Copy the files from `app/heroes` into the new crisis center folder.
- In the new files, change every mention of "hero" to "crisis", and "heroes" to "crises". * In the new files, change every mention of "hero" to "crisis", and "heroes" to "crises".
You'll turn the `CrisisService` into a purveyor of mock crises instead of mock heroes: You'll turn the `CrisisService` into a purveyor of mock crises instead of mock heroes:
@ -1591,9 +1610,9 @@ a#child-routing-component
:marked :marked
The `CrisisCenterComponent` has the following in common with the `AppComponent`: The `CrisisCenterComponent` has the following in common with the `AppComponent`:
- It is the *root* of the crisis center area, * It is the *root* of the crisis center area,
just as `AppComponent` is the root of the entire application. just as `AppComponent` is the root of the entire application.
- It is a *shell* for the crisis management feature area, * It is a *shell* for the crisis management feature area,
just as the `AppComponent` is a shell to manage the high-level workflow. just as the `AppComponent` is a shell to manage the high-level workflow.
Like most shells, the `CrisisCenterComponent` class is very simple, simpler even than `AppComponent`: Like most shells, the `CrisisCenterComponent` class is very simple, simpler even than `AppComponent`:
@ -1871,6 +1890,7 @@ code-example.
:marked :marked
The interesting part of the URL follows the `...`: The interesting part of the URL follows the `...`:
* The `crisis-center` is the primary navigation. * The `crisis-center` is the primary navigation.
* Parentheses surround the secondary route. * Parentheses surround the secondary route.
* The secondary route consists of an outlet name (`popup`), a `colon` separator, and the secondary route path (`compose`). * The secondary route consists of an outlet name (`popup`), a `colon` separator, and the secondary route path (`compose`).
@ -2364,6 +2384,7 @@ a#fetch-before-navigating
:marked :marked
**Two critical points** **Two critical points**
1. The router's `Resolve` interface is optional. 1. The router's `Resolve` interface is optional.
The `CrisisDetailResolver` doesn't inherit from a base class. The `CrisisDetailResolver` doesn't inherit from a base class.
The router looks for that method and calls it if found. The router looks for that method and calls it if found.
@ -2684,6 +2705,7 @@ a#custom-preloading
`SelectivePreloadingStrategy` implements the `PreloadingStrategy`, which has one method, `preload`. `SelectivePreloadingStrategy` implements the `PreloadingStrategy`, which has one method, `preload`.
The router calls the `preload` method with two arguments: The router calls the `preload` method with two arguments:
1. The route to consider. 1. The route to consider.
1. A loader function that can load the routed module asynchronously. 1. A loader function that can load the routed module asynchronously.
@ -2699,12 +2721,14 @@ a#custom-preloading
Shortly, you'll extend the `AdminDashboardComponent` to inject this service and display its `preloadedModules` array. Shortly, you'll extend the `AdminDashboardComponent` to inject this service and display its `preloadedModules` array.
But first, make a few changes to the `AppRoutingModule`. But first, make a few changes to the `AppRoutingModule`.
1. Import `SelectivePreloadingStrategy` into `AppRoutingModule`. 1. Import `SelectivePreloadingStrategy` into `AppRoutingModule`.
1. Replace the `PreloadAllModules` strategy in the call to `forRoot` with this `SelectivePreloadingStrategy`. 1. Replace the `PreloadAllModules` strategy in the call to `forRoot` with this `SelectivePreloadingStrategy`.
1. Add the `SelectivePreloadingStrategy` strategy to the `AppRoutingModule` providers array so it can be injected 1. Add the `SelectivePreloadingStrategy` strategy to the `AppRoutingModule` providers array so it can be injected
elsewhere in the app. elsewhere in the app.
Now edit the `AdminDashboardComponent` to display the log of preloaded routes. Now edit the `AdminDashboardComponent` to display the log of preloaded routes.
1. Import the `SelectivePreloadingStrategy` (it's a service). 1. Import the `SelectivePreloadingStrategy` (it's a service).
1. Inject it into the dashboard's constructor. 1. Inject it into the dashboard's constructor.
1. Update the template to display the strategy service's `preloadedModules` array. 1. Update the template to display the strategy service's `preloadedModules` array.

View File

@ -19,30 +19,38 @@ block includes
* [Demos](#demos) * [Demos](#demos)
* [Providing HTTP Services](#http-providers) * [Providing HTTP Services](#http-providers)
* [The Tour of Heroes *HTTP* client demo](#http-client) * [The Tour of Heroes *HTTP* client demo](#http-client)
- [The `HeroListComponent` class](#HeroListComponent)
* [The `HeroListComponent` class](#HeroListComponent)
* [Fetch data with `http.get()`](#fetch-data) * [Fetch data with `http.get()`](#fetch-data)
<li>[RxJS library](#rxjs-library) <li>[RxJS library](#rxjs-library)
<ul> <ul>
<li> [Enable RxJS operators](#enable-rxjs-operators)</li> <li> [Enable RxJS operators](#enable-rxjs-operators)</li>
</ul> </ul>
</li> </li>
* [Process the response object](#extract-data) * [Process the response object](#extract-data)
- [Parse to `JSON`](#parse-to-json)
- [Do not return the response object](#no-return-response-object) * [Parse to `JSON`](#parse-to-json)
- [Always handle errors](#error-handling) * [Do not return the response object](#no-return-response-object)
- [`HeroListComponent` error handling](#hero-list-component) * [Always handle errors](#error-handling)
* [`HeroListComponent` error handling](#hero-list-component)
* [Send data to the server](#update) * [Send data to the server](#update)
- [Headers](#headers)
- [JSON results](#json-results) * [Headers](#headers)
* [JSON results](#json-results)
<ul><li> [Fall back to promises](#promises)</ul> <ul><li> [Fall back to promises](#promises)</ul>
* [Cross-Origin Requests: Wikipedia example](#cors) * [Cross-Origin Requests: Wikipedia example](#cors)
<ul> <ul>
<li> [Search Wikipedia](#search-wikipedia)</li> <li> [Search Wikipedia](#search-wikipedia)</li>
<li> [Search parameters](#search-parameters)</li> <li> [Search parameters](#search-parameters)</li>
<li> [The WikiComponent](#wikicomponent)</li> <li> [The WikiComponent](#wikicomponent)</li>
</ul> </ul>
* [A wasteful app](#wasteful-app) * [A wasteful app](#wasteful-app)
<li> [More fun with Observables](#more-observables) <li> [More fun with Observables](#more-observables)
<ul> <ul>
@ -50,6 +58,7 @@ block includes
<li> [Listen for search terms](#listen-for-search-terms)</li> <li> [Listen for search terms](#listen-for-search-terms)</li>
</ul> </ul>
</li> </li>
* [Guarding against Cross-Site Request Forgery](#xsrf) * [Guarding against Cross-Site Request Forgery](#xsrf)
* [Override default request headers (and other request options)](#override-default-request-options) * [Override default request headers (and other request options)](#override-default-request-options)
* [Appendix: Tour of Heroes _in-memory web api_](#in-mem-web-api) * [Appendix: Tour of Heroes _in-memory web api_](#in-mem-web-api)
@ -65,10 +74,10 @@ a#demos
block demos-list block demos-list
:marked :marked
- [The Tour of Heroes *HTTP* client demo](#http-client). * [The Tour of Heroes *HTTP* client demo](#http-client).
- [Fall back to Promises](#promises). * [Fall back to Promises](#promises).
- [Cross-Origin Requests: Wikipedia example](#cors). * [Cross-Origin Requests: Wikipedia example](#cors).
- [More fun with Observables](#more-observables). * [More fun with Observables](#more-observables).
:marked :marked
The root `AppComponent` orchestrates these demos: The root `AppComponent` orchestrates these demos:

View File

@ -15,6 +15,7 @@ a#develop-locally
:marked :marked
Make sure you have [node and npm installed](#install-prerequisites "What if you don't have node and npm?"). Make sure you have [node and npm installed](#install-prerequisites "What if you don't have node and npm?").
Then ... Then ...
1. Create a project folder (you can call it `quickstart` and rename it later). 1. Create a project folder (you can call it `quickstart` and rename it later).
1. [Clone](#clone "Clone it from github") or [download](#download "download it from github") the **QuickStart seed** into your project folder. 1. [Clone](#clone "Clone it from github") or [download](#download "download it from github") the **QuickStart seed** into your project folder.
1. Install [npm](#install-prerequisites "What if you don't have node and npm?") packages. 1. Install [npm](#install-prerequisites "What if you don't have node and npm?") packages.
@ -206,6 +207,7 @@ a#why-locally
The other samples are based on the QuickStart seed. The other samples are based on the QuickStart seed.
As much fun as this is ... As much fun as this is ...
* you can't ship your app in plunker * you can't ship your app in plunker
* you aren't always online when writing code * you aren't always online when writing code
* transpiling TypeScript in the browser is slow * transpiling TypeScript in the browser is slow

View File

@ -12,18 +12,20 @@ style.
### Table of contents ### Table of contents
- [What are structural directives?](#definition) * [What are structural directives?](#definition)
- [*NgIf* case study](#ngIf) * [*NgIf* case study](#ngIf)
- [The asterisk (*) prefix](#asterisk) * [The asterisk (*) prefix](#asterisk)
- [Inside *NgFor*](#ngFor) * [Inside *NgFor*](#ngFor)
- [microsyntax](#microsyntax)
- [template input variables](#template-input-variable) * [microsyntax](#microsyntax)
- [one structural directive per element](#one-per-element) * [template input variables](#template-input-variable)
- [Inside the *NgSwitch* directives](#ngSwitch) * [one structural directive per element](#one-per-element)
- [Prefer the (*) prefix](#prefer-asterisk)
- [The &lt;template> element](#template) * [Inside the *NgSwitch* directives](#ngSwitch)
- [Group sibling elements with &lt;ng-container&gt;](#ng-container) * [Prefer the (*) prefix](#prefer-asterisk)
- [Write a structural directive](#unless) * [The &lt;template> element](#template)
* [Group sibling elements with &lt;ng-container&gt;](#ng-container)
* [Write a structural directive](#unless)
Try the <live-example></live-example>. Try the <live-example></live-example>.

View File

@ -31,18 +31,25 @@ a#toc
* [Two-way data binding ( <span class="syntax">[(...)]</span> )](#two-way) * [Two-way data binding ( <span class="syntax">[(...)]</span> )](#two-way)
* [Built-in directives](#directives) * [Built-in directives](#directives)
* [Built-in attribute directives](#attribute-directives) * [Built-in attribute directives](#attribute-directives)
* [NgClass](#ngClass) * [NgClass](#ngClass)
* [NgStyle](#ngStyle) * [NgStyle](#ngStyle)
* [NgModel (<span class="syntax">[(ngModel)]</span>) ](#ngModel) * [NgModel (<span class="syntax">[(ngModel)]</span>) ](#ngModel)
* [Built-in structural directives](#structural-directives) * [Built-in structural directives](#structural-directives)
* [NgIf](#ngIf) * [NgIf](#ngIf)
* [NgFor](#ngFor) * [NgFor](#ngFor)
* [Template input variables](#template-input-variables) * [Template input variables](#template-input-variables)
* [Microsyntax](#microsyntax) * [Microsyntax](#microsyntax)
* [The NgSwitch directives](#ngSwitch) * [The NgSwitch directives](#ngSwitch)
* [Template reference variables ( <span class="syntax">#var</span> )](#ref-vars) * [Template reference variables ( <span class="syntax">#var</span> )](#ref-vars)
* [Input and output properties ( <span class="syntax">@Input</span> and <span class="syntax">@Output</span> )](#inputs-outputs) * [Input and output properties ( <span class="syntax">@Input</span> and <span class="syntax">@Output</span> )](#inputs-outputs)
* [Template expression operators](#expression-operators) * [Template expression operators](#expression-operators)
* [pipe ( <span class="syntax">|</span> )](#pipe) * [pipe ( <span class="syntax">|</span> )](#pipe)
* [safe navigation operator ( <span class="syntax">?.</span> )](#safe-navigation-operator) * [safe navigation operator ( <span class="syntax">?.</span> )](#safe-navigation-operator)
@ -653,6 +660,7 @@ a#one-time-initialization
### One-time string initialization ### One-time string initialization
You *should* omit the brackets when all of the following are true: You *should* omit the brackets when all of the following are true:
* The target property accepts a string value. * The target property accepts a string value.
* The string is a fixed value that you can bake into the template. * The string is a fixed value that you can bake into the template.
* This initial value never changes. * This initial value never changes.
@ -1463,6 +1471,7 @@ a#trackBy
Here is an illustration of the _trackBy_ effect. Here is an illustration of the _trackBy_ effect.
"Reset heroes" creates new heroes with the same `hero.id`s. "Reset heroes" creates new heroes with the same `hero.id`s.
"Change ids" creates new heroes with new `hero.id`s. "Change ids" creates new heroes with new `hero.id`s.
* With no `trackBy`, both buttons trigger complete DOM element replacement. * With no `trackBy`, both buttons trigger complete DOM element replacement.
* With `trackBy`, only changing the `id` triggers element replacement. * With `trackBy`, only changing the `id` triggers element replacement.

View File

@ -13,83 +13,109 @@ a#top
* [Live examples](#live-examples "Live examples of the tests in this guide") * [Live examples](#live-examples "Live examples of the tests in this guide")
<br><br> <br><br>
* [Introduction to Angular testing](#testing-intro) * [Introduction to Angular testing](#testing-intro)
- [Tools and technologies](#tools-and-tech)
- [Setup](#setup) * [Tools and technologies](#tools-and-tech)
- [Isolated unit tests vs. the Angular testing utilities](#isolated-v-testing-utilities) * [Setup](#setup)
* [Isolated unit tests vs. the Angular testing utilities](#isolated-v-testing-utilities)
* [The first karma test](#1st-karma-test) * [The first karma test](#1st-karma-test)
- [Run with karma](#run-karma)
- [Test debugging](#test-debugging) * [Run with karma](#run-karma)
- [Try the live example](#live-karma-example) * [Test debugging](#test-debugging)
* [Try the live example](#live-karma-example)
* [Test a component](#simple-component-test) * [Test a component](#simple-component-test)
- [_TestBed_](#testbed)
- [_createComponent_](#create-component) * [_TestBed_](#testbed)
- [_ComponentFixture_, _DebugElement_, and _query(By.css)_](#component-fixture) * [_createComponent_](#create-component)
- [The tests](#the-tests) * [_ComponentFixture_, _DebugElement_, and _query(By.css)_](#component-fixture)
- [_detectChanges_: Angular change detection within a test](#detect-changes) * [The tests](#the-tests)
- [Try the live example](#try-example) * [_detectChanges_: Angular change detection within a test](#detect-changes)
- [Automatic change detection](#auto-detect-changes) * [Try the live example](#try-example)
* [Automatic change detection](#auto-detect-changes)
* [Test a component with an external template](#component-with-external-template) * [Test a component with an external template](#component-with-external-template)
- [The first asynchronous _beforeEach_](#async-in-before-each)
- [_compileComponents_](#compile-components) * [The first asynchronous _beforeEach_](#async-in-before-each)
- [The second synchronous _beforeEach_](#second-before-each) * [_compileComponents_](#compile-components)
- [Waiting for _compileComponents_](#waiting-compile-components) * [The second synchronous _beforeEach_](#second-before-each)
- [Try the live example](#live-external-template-example) * [Waiting for _compileComponents_](#waiting-compile-components)
* [Try the live example](#live-external-template-example)
* [Test a component with a service dependency](#component-with-dependency) * [Test a component with a service dependency](#component-with-dependency)
- [Provide service test doubles](#service-test-doubles)
- [Get injected services](#get-injected-service) * [Provide service test doubles](#service-test-doubles)
- [_TestBed.get_](#testbed-get) * [Get injected services](#get-injected-service)
- [Always get the service from an injector](#service-from-injector) * [_TestBed.get_](#testbed-get)
- [Final setup and tests](#welcome-spec-setup) * [Always get the service from an injector](#service-from-injector)
* [Final setup and tests](#welcome-spec-setup)
* [Test a component with an async service](#component-with-async-service) * [Test a component with an async service](#component-with-async-service)
- [Spying on the real service](#service-spy)
- [Synchronous tests](#sync-tests) * [Spying on the real service](#service-spy)
- [The _async_ funciton in it](#async) * [Synchronous tests](#sync-tests)
- [_whenStable_](#when-stable) * [The _async_ funciton in it](#async)
- [The _fakeAsync_ function](#fake-async) * [_whenStable_](#when-stable)
- [The _tick_ function](#tick) * [The _fakeAsync_ function](#fake-async)
- [_jasmine.done_](#jasmine-done) * [The _tick_ function](#tick)
* [_jasmine.done_](#jasmine-done)
* [Test a component with inputs and outputs](#component-with-input-output) * [Test a component with inputs and outputs](#component-with-input-output)
- [Test _DashboardHeroComponent_ stand-alone](#dashboard-standalone)
- [_triggerEventHandler_](#trigger-event-handler) * [Test _DashboardHeroComponent_ stand-alone](#dashboard-standalone)
* [_triggerEventHandler_](#trigger-event-handler)
* [Test a component inside a test host component](#component-inside-test-host) * [Test a component inside a test host component](#component-inside-test-host)
<br><br>
* [Test a routed component](#routed-component) * [Test a routed component](#routed-component)
- [The _inject_ helper function](#inject)
- [Test a routed component with parameters](#routed-component-w-param) * [The _inject_ helper function](#inject)
- [Create an _Observable_ test double](#stub-observable) * [Test a routed component with parameters](#routed-component-w-param)
- [Testing with the _Observable_ test double](#tests-w-observable-double) * [Create an _Observable_ test double](#stub-observable)
* [Testing with the _Observable_ test double](#tests-w-observable-double)
* [Use a _page_ object to simplify setup](#page-object) * [Use a _page_ object to simplify setup](#page-object)
* [Set up with module imports](#import-module) * [Set up with module imports](#import-module)
* [Import the feature module](#feature-module-import) * [Import the feature module](#feature-module-import)
<br><br> <br><br>
* [Override a component's providers](#component-override) * [Override a component's providers](#component-override)
- [The _overrideComponent_ method](#override-component-method)
- [Provide a _spy-stub (HeroDetailServiceSpy)_](#spy-stub) * [The _overrideComponent_ method](#override-component-method)
- [The override tests](#override-tests) * [Provide a _spy-stub (HeroDetailServiceSpy)_](#spy-stub)
- [More overrides](#more-overrides) * [The override tests](#override-tests)
* [More overrides](#more-overrides)
* [Test a _RouterOutlet_ component](#router-outlet-component) * [Test a _RouterOutlet_ component](#router-outlet-component)
- [Stubbing unneeded components](#stub-component)
- [Stubbing the _RouterLink_](#router-link-stub) * [Stubbing unneeded components](#stub-component)
- [_By.directive_ and injected directives](#by-directive) * [Stubbing the _RouterLink_](#router-link-stub)
- [What good are these tests?](#why-stubbed-routerlink-tests) * [_By.directive_ and injected directives](#by-directive)
* [What good are these tests?](#why-stubbed-routerlink-tests)
* ["Shallow component tests" with *NO\_ERRORS\_SCHEMA*](#shallow-component-test) * ["Shallow component tests" with *NO\_ERRORS\_SCHEMA*](#shallow-component-test)
<br><br> <br><br>
* [Test an attribute directive](#attribute-directive) * [Test an attribute directive](#attribute-directive)
<br><br> <br><br>
* [Isolated unit tests](#isolated-unit-tests "Unit testing without the Angular testing utilities") * [Isolated unit tests](#isolated-unit-tests "Unit testing without the Angular testing utilities")
- [Services](#isolated-service-tests)
- [Services with dependencies](#services-with-dependencies) * [Services](#isolated-service-tests)
- [Pipes](#isolated-pipe-tests) * [Services with dependencies](#services-with-dependencies)
- [Write Angular tests too](#write-tests) * [Pipes](#isolated-pipe-tests)
- [Components](#isolated-component-tests) * [Write Angular tests too](#write-tests)
* [Components](#isolated-component-tests)
* [Angular testing utility APIs](#atu-apis) * [Angular testing utility APIs](#atu-apis)
- [_TestBed_ class summary](#testbed-class-summary)
- [The _ComponentFixture_](#component-fixture-api-summary) * [_TestBed_ class summary](#testbed-class-summary)
- [_ComponentFixture_ properties](#component-fixture-properties) * [The _ComponentFixture_](#component-fixture-api-summary)
- [The _ComponentFixture_ methods](#component-fixture-methods) * [_ComponentFixture_ properties](#component-fixture-properties)
- [_DebugElement_](#debug-element-details) * [The _ComponentFixture_ methods](#component-fixture-methods)
* [_DebugElement_](#debug-element-details)
* [Test environment setup files](#setup-files) * [Test environment setup files](#setup-files)
- [npm packages](#npm-packages)
* [npm packages](#npm-packages)
* [FAQ: Frequently asked questions](#faq "Frequently asked questions") * [FAQ: Frequently asked questions](#faq "Frequently asked questions")
:marked :marked
Its a big agenda. Fortunately, you can learn a little bit at a time and put each lesson to use. Its a big agenda. Fortunately, you can learn a little bit at a time and put each lesson to use.
@ -927,9 +953,10 @@ a#component-with-input-output
:marked :marked
While testing a component this simple has little intrinsic value, it's worth knowing how. While testing a component this simple has little intrinsic value, it's worth knowing how.
You can use one of these approaches: You can use one of these approaches:
- Test it as used by `DashboardComponent`.
- Test it as a stand-alone component. * Test it as used by `DashboardComponent`.
- Test it as used by a substitute for `DashboardComponent`. * Test it as a stand-alone component.
* Test it as used by a substitute for `DashboardComponent`.
A quick look at the `DashboardComponent` constructor discourages the first approach: A quick look at the `DashboardComponent` constructor discourages the first approach:
+makeExample('testing/ts/src/app/dashboard/dashboard.component.ts', 'ctor', 'src/app/dashboard/dashboard.component.ts (constructor)')(format='.') +makeExample('testing/ts/src/app/dashboard/dashboard.component.ts', 'ctor', 'src/app/dashboard/dashboard.component.ts (constructor)')(format='.')
@ -1062,6 +1089,7 @@ a#component-inside-test-host
+makeExample('testing/ts/src/app/dashboard/dashboard-hero.component.spec.ts', 'test-host-setup', 'src/app/dashboard/dashboard-hero.component.spec.ts (test host setup)')(format='.') +makeExample('testing/ts/src/app/dashboard/dashboard-hero.component.spec.ts', 'test-host-setup', 'src/app/dashboard/dashboard-hero.component.spec.ts (test host setup)')(format='.')
:marked :marked
This testing module configuration shows two important differences: This testing module configuration shows two important differences:
1. It _declares_ both the `DashboardHeroComponent` and the `TestHostComponent`. 1. It _declares_ both the `DashboardHeroComponent` and the `TestHostComponent`.
1. It _creates_ the `TestHostComponent` instead of the `DashboardHeroComponent`. 1. It _creates_ the `TestHostComponent` instead of the `DashboardHeroComponent`.
@ -1122,6 +1150,7 @@ a#inject
It injects services into the test function where you can alter, spy on, and manipulate them. It injects services into the test function where you can alter, spy on, and manipulate them.
The `inject` function has two parameters: The `inject` function has two parameters:
1. An array of Angular dependency injection tokens. 1. An array of Angular dependency injection tokens.
1. A test function whose parameters correspond exactly to each item in the injection token array. 1. A test function whose parameters correspond exactly to each item in the injection token array.
@ -1259,6 +1288,7 @@ figure.image-display
+makeExample('testing/ts/src/app/hero/hero-detail.component.html', '', 'src/app/hero/hero-detail.component.html')(format='.') +makeExample('testing/ts/src/app/hero/hero-detail.component.html', '', 'src/app/hero/hero-detail.component.html')(format='.')
:marked :marked
To fully exercise the component, the test needs a lot of setup: To fully exercise the component, the test needs a lot of setup:
* It must wait until a hero arrives before `*ngIf` allows any element in DOM. * It must wait until a hero arrives before `*ngIf` allows any element in DOM.
* It needs references to the title `<span>` and the name `<input>` so it can inspect their values. * It needs references to the title `<span>` and the name `<input>` so it can inspect their values.
* It needs references to the two buttons so it can click them. * It needs references to the two buttons so it can click them.
@ -1304,6 +1334,7 @@ a#import-module
The `HeroDetailComponent` requires a lot of help despite its small size and simple construction. The `HeroDetailComponent` requires a lot of help despite its small size and simple construction.
In addition to the support it receives from the default testing module `CommonModule`, it needs: In addition to the support it receives from the default testing module `CommonModule`, it needs:
* `NgModel` and friends in the `FormsModule` to enable two-way data binding. * `NgModel` and friends in the `FormsModule` to enable two-way data binding.
* The `TitleCasePipe` from the `shared` folder. * The `TitleCasePipe` from the `shared` folder.
* Router services (which these tests are stubbing). * Router services (which these tests are stubbing).
@ -1651,6 +1682,7 @@ figure.image-display
`By.css('*:not([highlight])')` finds _any_ element that does not have the directive. `By.css('*:not([highlight])')` finds _any_ element that does not have the directive.
// Removed on 12/02/2016 when ceased public discussion of the `Renderer`. Revive in future? // Removed on 12/02/2016 when ceased public discussion of the `Renderer`. Revive in future?
* `DebugElement.styles` affords access to element styles even in the absence of a real browser, thanks to the `DebugElement` abstraction. * `DebugElement.styles` affords access to element styles even in the absence of a real browser, thanks to the `DebugElement` abstraction.
But feel free to exploit the `nativeElement` when that seems easier or more clear than the abstraction. But feel free to exploit the `nativeElement` when that seems easier or more clear than the abstraction.
@ -1660,6 +1692,7 @@ figure.image-display
and its `defaultColor`. and its `defaultColor`.
// Removed on 12/02/2016 when ceased public discussion of the `Renderer`. Revive in future? // Removed on 12/02/2016 when ceased public discussion of the `Renderer`. Revive in future?
* `DebugElement.properties` affords access to the artificial custom property that is set by the directive. * `DebugElement.properties` affords access to the artificial custom property that is set by the directive.
a(href="#top").to-top Back to top a(href="#top").to-top Back to top
@ -1677,12 +1710,14 @@ a#isolated-unit-tests
Such tests are often smaller and easier to read, write, and maintain. Such tests are often smaller and easier to read, write, and maintain.
They don't carry extra baggage: They don't carry extra baggage:
* Import from the Angular test libraries. * Import from the Angular test libraries.
* Configure a module. * Configure a module.
* Prepare dependency injection `providers`. * Prepare dependency injection `providers`.
* Call `inject` or `async` or `fakeAsync`. * Call `inject` or `async` or `fakeAsync`.
They follow patterns familiar to test developers everywhere: They follow patterns familiar to test developers everywhere:
* Exhibit standard, Angular-agnostic testing techniques. * Exhibit standard, Angular-agnostic testing techniques.
* Create instances directly with `new`. * Create instances directly with `new`.
* Substitute test doubles (stubs, spys, and mocks) for the real dependencies. * Substitute test doubles (stubs, spys, and mocks) for the real dependencies.
@ -2293,6 +2328,7 @@ a#query-predicate
:marked :marked
The Angular `By` class has three static methods for common predicates: The Angular `By` class has three static methods for common predicates:
* `By.all` - return all elements. * `By.all` - return all elements.
* `By.css(selector)` - return elements with matching CSS selectors. * `By.css(selector)` - return elements with matching CSS selectors.
* `By.directive(directive)` - return elements that Angular matched to an instance of the directive class. * `By.directive(directive)` - return elements that Angular matched to an instance of the directive class.
@ -2351,6 +2387,7 @@ a(href="#top").to-top Back to top
a#setup-files a#setup-files
:marked :marked
## Test environment setup files ## Test environment setup files
Unit testing requires some configuration and bootstrapping that is captured in _setup files_. Unit testing requires some configuration and bootstrapping that is captured in _setup files_.
The setup files for this guide are provided for you when you follow the [Setup](setup.html) instructions. The setup files for this guide are provided for you when you follow the [Setup](setup.html) instructions.
The CLI delivers similar files with the same purpose. The CLI delivers similar files with the same purpose.
@ -2429,6 +2466,7 @@ a(href="#top").to-top Back to top
// //
:marked :marked
General General
* [When are end-to-end (e2e) tests a good choice?](#q-when-e2e) * [When are end-to-end (e2e) tests a good choice?](#q-when-e2e)
* [When to use the _TestBed_?](#q-why-testbed) * [When to use the _TestBed_?](#q-why-testbed)
* [When to write isolated unit tests without the _TestBed_?](#q-when-no-testbed) * [When to write isolated unit tests without the _TestBed_?](#q-when-no-testbed)
@ -2451,6 +2489,7 @@ a(href="#top").to-top Back to top
* [How do I use the Jasmine HTML TestRunner in the browser?](#q-jasmine-browser-test-runner) * [How do I use the Jasmine HTML TestRunner in the browser?](#q-jasmine-browser-test-runner)
Resources Resources
* [Where can I learn more about unit testing in JavaScript?](#q-js-unit-testing-resources) * [Where can I learn more about unit testing in JavaScript?](#q-js-unit-testing-resources)
* [Where can I learn more about testing with Jasmine?](#q-jasmine-resources) * [Where can I learn more about testing with Jasmine?](#q-jasmine-resources)
* [Where can I learn more about testing with karma?](#q-karma-resources) * [Where can I learn more about testing with karma?](#q-karma-resources)
@ -2466,11 +2505,12 @@ a(href="#top").to-top Back to top
It's a good idea to put unit test spec files in the same folder It's a good idea to put unit test spec files in the same folder
as the application source code files that they test: as the application source code files that they test:
- Such tests are easy to find.
- You see at a glance if a part of your application lacks tests. * Such tests are easy to find.
- Nearby tests can reveal how a part works in context. * You see at a glance if a part of your application lacks tests.
- When you move the source (inevitable), you remember to move the test. * Nearby tests can reveal how a part works in context.
- When you rename the source file (inevitable), you remember to rename the test file. * When you move the source (inevitable), you remember to move the test.
* When you rename the source file (inevitable), you remember to rename the test file.
.l-hr .l-hr

View File

@ -6,39 +6,59 @@
## Table of Contents ## Table of Contents
* [Overview](#overview) * [Overview](#overview)
* [How does it work?](#how-does-it-work) * [How does it work?](#how-does-it-work)
* [Why do it?](#why-do-it) * [Why do it?](#why-do-it)
* [SEO / No JavaScript](#seo-no-javascript) * [SEO / No JavaScript](#seo-no-javascript)
* [Startup Performance](#startup-performance) * [Startup Performance](#startup-performance)
* [The Example](#the-example) * [The Example](#the-example)
* [Preparation](#preparation) * [Preparation](#preparation)
* [Installing the tools](#installing-the-tools) * [Installing the tools](#installing-the-tools)
* [Component-relative URLs](#component-relative-urls) * [Component-relative URLs](#component-relative-urls)
* [Server Transition](#server-transition) * [Server Transition](#server-transition)
* [Configuration - AOT](#configuration-aot) * [Configuration - AOT](#configuration-aot)
* [Main Entry Point](#main-entry-point) * [Main Entry Point](#main-entry-point)
* [Creating the tsconfig-aot.json](#creating-the-tsconfig-aot-json) * [Creating the tsconfig-aot.json](#creating-the-tsconfig-aot-json)
* [Webpack Configuration](#webpack-configuration) * [Webpack Configuration](#webpack-configuration)
* [Loader](#loader) * [Loader](#loader)
* [Plugin](#plugin) * [Plugin](#plugin)
* [Input](#input) * [Input](#input)
* [Output](#output) * [Output](#output)
* [Build - AOT](#build-aot) * [Build - AOT](#build-aot)
* [Source Maps](#source-maps) * [Source Maps](#source-maps)
* [Serve - AOT](#serve-aot) * [Serve - AOT](#serve-aot)
* [Lite Server Configuration](#lite-server-configuration) * [Lite Server Configuration](#lite-server-configuration)
* [Serve Command](#serve-command) * [Serve Command](#serve-command)
* [Configuration - Universal](#configuration-universal) * [Configuration - Universal](#configuration-universal)
* [Server Code](#server-code) * [Server Code](#server-code)
* [App Server Module](#app-server-module) * [App Server Module](#app-server-module)
* [Universal Engine](#universal-engine) * [Universal Engine](#universal-engine)
* [Web Server](#web-server) * [Web Server](#web-server)
* [Creating the tsconfig-uni.json](#creating-the-tsconfig-uni-json) * [Creating the tsconfig-uni.json](#creating-the-tsconfig-uni-json)
* [Creating the webpack.config.uni.js](#creating-the-webpack-config-uni-js) * [Creating the webpack.config.uni.js](#creating-the-webpack-config-uni-js)
* [The entry points](#the-entry-points) * [The entry points](#the-entry-points)
* [The output file](#the-output-file) * [The output file](#the-output-file)
* [Build and Serve - Universal](#build-and-serve-universal) * [Build and Serve - Universal](#build-and-serve-universal)
* [Exercising Universal](#exercising-universal) * [Exercising Universal](#exercising-universal)
* [Disabling the Client App](#disabling-the-client-app) * [Disabling the Client App](#disabling-the-client-app)
* [Throttling](#throttling) * [Throttling](#throttling)
* [Conclusion](#conclusion) * [Conclusion](#conclusion)
@ -158,19 +178,19 @@ The AOT and Universal versions of the app are both compiled by the AOT compiler.
To build and run the AOT version, you need to create: To build and run the AOT version, you need to create:
- an `index-aot.html` file * an `index-aot.html` file
- a main entry point, `main-aot.ts` * a main entry point, `main-aot.ts`
- a TypeScript config file, `tsconfig-aot.json` * a TypeScript config file, `tsconfig-aot.json`
- a Webpack config file, `webpack.config.aot.js` * a Webpack config file, `webpack.config.aot.js`
- a lite-server config file, `bs-config.aot.js` * a lite-server config file, `bs-config.aot.js`
To build and run the Universal version, you need to create: To build and run the Universal version, you need to create:
- a server-side app module, `app.server.ts` * a server-side app module, `app.server.ts`
- a Universal app renderer, `universal-engine.ts` * a Universal app renderer, `universal-engine.ts`
- an express web server to handle requests, `server-aot.ts` * an express web server to handle requests, `server-aot.ts`
- a TypeScript config file, `tsconfig-uni.json` * a TypeScript config file, `tsconfig-uni.json`
- a Webpack config file, `webpack.config.uni.js` * a Webpack config file, `webpack.config.uni.js`
The folder structure will look like this: The folder structure will look like this:
@ -206,12 +226,12 @@ The files marked with * are new and not in the original Tour of Heroes demo. Th
To get started, you need to install the necessary modules for AOT and Webpack. To get started, you need to install the necessary modules for AOT and Webpack.
- `@angular/compiler-cli` - The ngc compiler that compiles Angular applications * `@angular/compiler-cli` - The ngc compiler that compiles Angular applications
- `@angular/platform-server` - Server-side components needed for compilation * `@angular/platform-server` - Server-side components needed for compilation
- `webpack` - The Webpack JavaScript bundler * `webpack` - The Webpack JavaScript bundler
- `@ngtools/webpack` - The Webpack loader and plugin for bundling compiled applications * `@ngtools/webpack` - The Webpack loader and plugin for bundling compiled applications
- `raw-loader` - The Webpack loader for text files * `raw-loader` - The Webpack loader for text files
- `express` - The web server for serving the Universal application * `express` - The web server for serving the Universal application
You can install them with the following commands: You can install them with the following commands:
@ -306,13 +326,14 @@ Since `app.module.ts` appears first in the array, it will be compiled into an `n
The AOT compiler transpiles TypeScript into JavaScript (like `tsc`), and compiles your app's components, services, etc. into executable JavaScript code. The AOT compiler transpiles TypeScript into JavaScript (like `tsc`), and compiles your app's components, services, etc. into executable JavaScript code.
You configure it using a JSON file similar to `tsconfig.json`. There are a few differences: You configure it using a JSON file similar to `tsconfig.json`. There are a few differences:
- The `module` setting must be `es2015`. * The `module` setting must be `es2015`.
This creates JavaScript output with `import` statements (instead of `require()`) that can be compiled and bundled. This creates JavaScript output with `import` statements (instead of `require()`) that can be compiled and bundled.
- The `files` setting includes the app module and the main AOT bootstrapper. See more about this in the section below. * The `files` setting includes the app module and the main AOT bootstrapper. See more about this in the section below.
- There is a new `angularCompilerOptions` section with the following settings: * There is a new `angularCompilerOptions` section with the following settings:
- `genDir` - the output directory that will contain the compiled `ngfactory` code. When compiling via Webpack, this is used as a temporary directory.
- `entryModule` - the root module of the app, expressed as **path/to/file#ClassName**. * `genDir` - the output directory that will contain the compiled `ngfactory` code. When compiling via Webpack, this is used as a temporary directory.
- `skipMetadataEmit` - set to `true` because you don't need metadata in the bundled application * `entryModule` - the root module of the app, expressed as **path/to/file#ClassName**.
* `skipMetadataEmit` - set to `true` because you don't need metadata in the bundled application
Create a `tsconfig-aot.json` file in the project rood directory by copying your `tsconfig.json` and applying the changes described above. It should look like this: Create a `tsconfig-aot.json` file in the project rood directory by copying your `tsconfig.json` and applying the changes described above. It should look like this:
@ -809,10 +830,3 @@ Now rename `build.tmp.js` back to `build.js` so the app can load again. Then op
# Conclusion <a name="conclusion"></a> # Conclusion <a name="conclusion"></a>
Angular Universal can greatly improve the perceived startup performance of your app. The slower the network, the more advantageous it becomes to have Universal display the first page to the user. Angular Universal can greatly improve the perceived startup performance of your app. The slower the network, the more advantageous it becomes to have Universal display the first page to the user.

View File

@ -27,11 +27,14 @@ include ../_util-fns
make incremental upgrading seamless. make incremental upgrading seamless.
1. [Preparation](#preparation) 1. [Preparation](#preparation)
1. [Follow the Angular Style Guide](#follow-the-angular-style-guide) 1. [Follow the Angular Style Guide](#follow-the-angular-style-guide)
2. [Using a Module Loader](#using-a-module-loader) 2. [Using a Module Loader](#using-a-module-loader)
3. [Migrating to TypeScript](#migrating-to-typescript) 3. [Migrating to TypeScript](#migrating-to-typescript)
4. [Using Component Directives](#using-component-directives) 4. [Using Component Directives](#using-component-directives)
2. [Upgrading with The Upgrade Module](#upgrading-with-the-upgrade-module) 2. [Upgrading with The Upgrade Module](#upgrading-with-the-upgrade-module)
1. [How The Upgrade Module Works](#how-the-upgrade-module-works) 1. [How The Upgrade Module Works](#how-the-upgrade-module-works)
2. [Bootstrapping hybrid](#bootstrapping-hybrid-applications) 2. [Bootstrapping hybrid](#bootstrapping-hybrid-applications)
3. [Using Angular Components from AngularJS Code](#using-angular-components-from-angularjs-code) 3. [Using Angular Components from AngularJS Code](#using-angular-components-from-angularjs-code)
@ -42,7 +45,9 @@ include ../_util-fns
8. [Making Angular Dependencies Injectable to AngularJS](#making-angular-dependencies-injectable-to-angularjs) 8. [Making Angular Dependencies Injectable to AngularJS](#making-angular-dependencies-injectable-to-angularjs)
9. [Using Ahead-of-time compilation with hybrid apps](#using-ahead-of-time-compilation-with-hybrid-apps) 9. [Using Ahead-of-time compilation with hybrid apps](#using-ahead-of-time-compilation-with-hybrid-apps)
10. [Dividing routes between Angular and AngularJS](#dividing-routes-between-angular-and-angularjs) 10. [Dividing routes between Angular and AngularJS](#dividing-routes-between-angular-and-angularjs)
3. [PhoneCat Upgrade Tutorial](#phonecat-upgrade-tutorial) 3. [PhoneCat Upgrade Tutorial](#phonecat-upgrade-tutorial)
1. [Switching to TypeScript](#switching-to-typescript) 1. [Switching to TypeScript](#switching-to-typescript)
2. [Installing Angular](#installing-angular) 2. [Installing Angular](#installing-angular)
3. [Bootstrapping a hybrid PhoneCat](#bootstrapping-a-hybrid-phonecat) 3. [Bootstrapping a hybrid PhoneCat](#bootstrapping-a-hybrid-phonecat)
@ -51,6 +56,7 @@ include ../_util-fns
6. [AoT compile the hybrid app](#aot-compile-the-hybrid-app) 6. [AoT compile the hybrid app](#aot-compile-the-hybrid-app)
7. [Adding The Angular Router And Bootstrap](#adding-the-angular-router-and-bootstrap) 7. [Adding The Angular Router And Bootstrap](#adding-the-angular-router-and-bootstrap)
8. [Say Goodbye to AngularJS](#say-goodbye-to-angularjs) 8. [Say Goodbye to AngularJS](#say-goodbye-to-angularjs)
3. [Appendix: Upgrading PhoneCat Tests](#appendix-upgrading-phonecat-tests) 3. [Appendix: Upgrading PhoneCat Tests](#appendix-upgrading-phonecat-tests)
.l-main-section .l-main-section
@ -79,6 +85,7 @@ include ../_util-fns
aligned with Angular*. aligned with Angular*.
There are a few rules in particular that will make it much easier to do There are a few rules in particular that will make it much easier to do
*an incremental upgrade* using the Angular `upgrade` module: *an incremental upgrade* using the Angular `upgrade` module:
* The [Rule of 1](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#single-responsibility) * The [Rule of 1](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#single-responsibility)
@ -270,11 +277,12 @@ table
interoperability. The `UpgradeModule` resolves the differences and makes interoperability. The `UpgradeModule` resolves the differences and makes
everything work seamlessly: everything work seamlessly:
* We can make AngularJS services available for injection to Angular code * You can make AngularJS services available for injection to Angular code
by *upgrading* them. The same singleton instance of each service is shared by *upgrading* them. The same singleton instance of each service is shared
between the frameworks. In Angular these services will always be in the between the frameworks. In Angular these services will always be in the
*root injector* and available to all components. *root injector* and available to all components.
* We can also make Angular services available for injection to AngularJS code
* You can also make Angular services available for injection to AngularJS code
by *downgrading* them. Only services from the Angular root injector can by *downgrading* them. Only services from the Angular root injector can
be downgraded. Again, the same singleton instances are shared between the frameworks. be downgraded. Again, the same singleton instances are shared between the frameworks.
When we register a downgrade, we explicitly specify a *string token* that we want to When we register a downgrade, we explicitly specify a *string token* that we want to
@ -300,6 +308,7 @@ figure.image-display
frameworks. The other framework ignores it. If an element is frameworks. The other framework ignores it. If an element is
owned by AngularJS, Angular treats it as if it didn't exist, owned by AngularJS, Angular treats it as if it didn't exist,
and vice versa. and vice versa.
2. The root of the application *is always an AngularJS template*. 2. The root of the application *is always an AngularJS template*.
So a hybrid application begins life as an AngularJS application, So a hybrid application begins life as an AngularJS application,
@ -316,6 +325,7 @@ figure.image-display
1. By using a component from the other framework: An AngularJS template 1. By using a component from the other framework: An AngularJS template
using an Angular component, or an Angular template using an using an Angular component, or an Angular template using an
AngularJS component. AngularJS component.
2. By transcluding or projecting content from the other framework. The 2. By transcluding or projecting content from the other framework. The
`UpgradeModule` bridges the related concepts of AngularJS transclusion `UpgradeModule` bridges the related concepts of AngularJS transclusion
and Angular content projection together. and Angular content projection together.

View File

@ -17,24 +17,30 @@ style.
# Contents # Contents
* [What is Webpack?](#what-is-webpack) * [What is Webpack?](#what-is-webpack)
* [Entries and outputs](#entries-outputs) * [Entries and outputs](#entries-outputs)
* [Multiple bundles](#multiple-bundles) * [Multiple bundles](#multiple-bundles)
* [Loaders](#loaders) * [Loaders](#loaders)
* [Plugins](#plugins) * [Plugins](#plugins)
* [Configuring Webpack](#configure-webpack) * [Configuring Webpack](#configure-webpack)
* [Polyfills](#polyfills) * [Polyfills](#polyfills)
* [Common configuration](#common-configuration) * [Common configuration](#common-configuration)
* [Inside `webpack.common.js`](#inside-webpack-commonjs) * [Inside `webpack.common.js`](#inside-webpack-commonjs)
- [entry](#common-entries)
- [resolve extension-less imports](#common-resolves) * [entry](#common-entries)
- [`module.rules`](#common-rules) * [resolve extension-less imports](#common-resolves)
- [Plugins](#plugins) * [`module.rules`](#common-rules)
- [`CommonsChunkPlugin`](#commons-chunk-plugin) * [Plugins](#plugins)
- [`HtmlWebpackPlugin`](#html-webpack-plugin) * [`CommonsChunkPlugin`](#commons-chunk-plugin)
* [`HtmlWebpackPlugin`](#html-webpack-plugin)
* [Environment specific configuration](#environment-configuration) * [Environment specific configuration](#environment-configuration)
* [Development configuration](#development-configuration) * [Development configuration](#development-configuration)
* [Production configuration](#production-configuration) * [Production configuration](#production-configuration)
* [Test configuration](#test-configuration) * [Test configuration](#test-configuration)
* [Trying it out](#try) * [Trying it out](#try)
* [Highlights](#highlights) * [Highlights](#highlights)
* [Conclusion](#conclusion) * [Conclusion](#conclusion)

View File

@ -155,6 +155,7 @@ code-example(language="sh" class="code-shell").
.l-main-section .l-main-section
:marked :marked
## The road you've travelled ## The road you've travelled
Take stock of what you've built. Take stock of what you've built.
* The Tour of Heroes app uses the double curly braces of interpolation (a type of one-way data binding) * The Tour of Heroes app uses the double curly braces of interpolation (a type of one-way data binding)

View File

@ -276,6 +276,7 @@ code-example(language="sh" class="code-shell").
.l-main-section .l-main-section
:marked :marked
## The road you've travelled ## The road you've travelled
Here's what you achieved in this page: Here's what you achieved in this page:
* The Tour of Heroes app displays a list of selectable heroes. * The Tour of Heroes app displays a list of selectable heroes.

View File

@ -243,6 +243,7 @@ a#add-hero-detail
.l-main-section .l-main-section
:marked :marked
## The road youve travelled ## The road youve travelled
Here's what you achieved in this page: Here's what you achieved in this page:
* You created a reusable component. * You created a reusable component.

View File

@ -152,6 +152,7 @@ code-example(language="sh" class="code-shell").
### Inject the *HeroService* ### Inject the *HeroService*
Instead of using the *new* line, you'll add two lines. Instead of using the *new* line, you'll add two lines.
* Add a constructor that also defines a private property. * Add a constructor that also defines a private property.
* Add to the component's `providers` metadata. * Add to the component's `providers` metadata.

View File

@ -100,6 +100,7 @@ include ../../../_includes/_see-addr-bar
and create a separate `AppComponent` shell. and create a separate `AppComponent` shell.
Do the following: Do the following:
* Rename the <code>app.component.ts</code> file to <code>heroes.component.ts</code>. * Rename the <code>app.component.ts</code> file to <code>heroes.component.ts</code>.
* Rename the `AppComponent` class as `HeroesComponent` (rename locally, _only_ in this file). * Rename the `AppComponent` class as `HeroesComponent` (rename locally, _only_ in this file).
* Rename the selector `my-app` as `my-heroes`. * Rename the selector `my-app` as `my-heroes`.
@ -118,8 +119,10 @@ include ../../../_includes/_see-addr-bar
* Define an exported `AppComponent` class. * Define an exported `AppComponent` class.
* Add an `@Component` decorator above the class with a `my-app` selector. * Add an `@Component` decorator above the class with a `my-app` selector.
* Move the following from `HeroesComponent` to `AppComponent`: * Move the following from `HeroesComponent` to `AppComponent`:
* `title` class property. * `title` class property.
* `@Component` template `<h1>` element, which contains a binding to `title`. * `@Component` template `<h1>` element, which contains a binding to `title`.
* Add a `<my-heroes>` element to the app template just below the heading so you still see the heroes. * Add a `<my-heroes>` element to the app template just below the heading so you still see the heroes.
* Add `HeroesComponent` to the `declarations` array of `AppModule` so Angular recognizes the `<my-heroes>` tags. * Add `HeroesComponent` to the `declarations` array of `AppModule` so Angular recognizes the `<my-heroes>` tags.
* Add `HeroService` to the `providers` array of `AppModule` because you'll need it in every other view. * Add `HeroService` to the `providers` array of `AppModule` because you'll need it in every other view.
@ -187,8 +190,8 @@ a#configure-routes
This route definition has the following parts: This route definition has the following parts:
- *Path*: The router matches this route's path to the URL in the browser address bar (`heroes`). * *Path*: The router matches this route's path to the URL in the browser address bar (`heroes`).
- *Component*: The component that the router should create when navigating to this route (`HeroesComponent`). * *Component*: The component that the router should create when navigating to this route (`HeroesComponent`).
.l-sub-section .l-sub-section
@ -603,6 +606,7 @@ code-example(format="nocode").
+makeExample('toh-5/ts/src/app/app-routing.module.ts', null, 'src/app/app-routing.module.ts') +makeExample('toh-5/ts/src/app/app-routing.module.ts', null, 'src/app/app-routing.module.ts')
:marked :marked
The following points are typical of routing modules: The following points are typical of routing modules:
* The Routing Module pulls the routes into a variable. The variable clarifies the * The Routing Module pulls the routes into a variable. The variable clarifies the
routing module pattern in case you export the module in the future. routing module pattern in case you export the module in the future.
* The Routing Module adds `RouterModule.forRoot(routes)` to `imports`. * The Routing Module adds `RouterModule.forRoot(routes)` to `imports`.
@ -878,12 +882,12 @@ figure.image-display
## The road youve travelled ## The road youve travelled
Here's what you achieved in this page: Here's what you achieved in this page:
- You added the Angular router to navigate among different components. * You added the Angular router to navigate among different components.
- You learned how to create router links to represent navigation menu items. * You learned how to create router links to represent navigation menu items.
- You used router link parameters to navigate to the details of the user-selected hero. * You used router link parameters to navigate to the details of the user-selected hero.
- You shared the `HeroService` among multiple components. * You shared the `HeroService` among multiple components.
- You moved HTML and CSS out of the component file and into their own files. * You moved HTML and CSS out of the component file and into their own files.
- You added the `uppercase` pipe to format data. * You added the `uppercase` pipe to format data.
Your app should look like this <live-example></live-example>. Your app should look like this <live-example></live-example>.

View File

@ -561,12 +561,12 @@ figure.image-display
## Home Stretch ## Home Stretch
You're at the end of your journey, and you've accomplished a lot. You're at the end of your journey, and you've accomplished a lot.
- You added the necessary dependencies to use HTTP in the app. * You added the necessary dependencies to use HTTP in the app.
- You refactored `HeroService` to load heroes from a web API. * You refactored `HeroService` to load heroes from a web API.
- You extended `HeroService` to support `post()`, `put()`, and `delete()` methods. * You extended `HeroService` to support `post()`, `put()`, and `delete()` methods.
- You updated the components to allow adding, editing, and deleting of heroes. * You updated the components to allow adding, editing, and deleting of heroes.
- You configured an in-memory web API. * You configured an in-memory web API.
- You learned how to use Observables. * You learned how to use Observables.
Here are the files you added or changed in this page. Here are the files you added or changed in this page.