refactor(aio): move content-related images to `content/images/`

This commit is contained in:
Georgios Kalpakas 2017-04-26 15:11:02 +03:00 committed by Pete Bacon Darwin
parent 2e5e37ac58
commit 6561d46349
237 changed files with 765 additions and 765 deletions

View File

@ -66,7 +66,7 @@ The examples in this page are available as a <live-example></live-example>.
## Quickstart example: Transitioning between two states
<figure>
<img src="assets/images/guide/animations/animation_basic_click.gif" alt="A simple transition animation" align="right" style="width:220px;margin-left:20px"></img>
<img src="content/images/guide/animations/animation_basic_click.gif" alt="A simple transition animation" align="right" style="width:220px;margin-left:20px"></img>
</figure>
@ -172,7 +172,7 @@ controls the timing of switching between one set of styles and the next:
<figure class='image-display'>
<img src="assets/images/guide/animations/ng_animate_transitions_inactive_active.png" alt="In Angular animations you define states and transitions between states" width="400"></img>
<img src="content/images/guide/animations/ng_animate_transitions_inactive_active.png" alt="In Angular animations you define states and transitions between states" width="400"></img>
</figure>
@ -220,7 +220,7 @@ transitions that apply regardless of which state the animation is in. For exampl
<figure class='image-display'>
<img src="assets/images/guide/animations/ng_animate_transitions_inactive_active_wildcards.png" alt="The wildcard state can be used to match many different transitions at once" width="400"></img>
<img src="content/images/guide/animations/ng_animate_transitions_inactive_active_wildcards.png" alt="The wildcard state can be used to match many different transitions at once" width="400"></img>
</figure>
@ -237,7 +237,7 @@ regardless of what state it was in before it left.
<figure class='image-display'>
<img src="assets/images/guide/animations/ng_animate_transitions_void_in.png" alt="The void state can be used for enter and leave transitions" width="400"></img>
<img src="content/images/guide/animations/ng_animate_transitions_void_in.png" alt="The void state can be used for enter and leave transitions" width="400"></img>
</figure>
@ -247,7 +247,7 @@ The wildcard state `*` also matches `void`.
## Example: Entering and leaving
<figure>
<img src="assets/images/guide/animations/animation_enter_leave.gif" alt="Enter and leave animations" align="right" style="width:250px;"></img>
<img src="content/images/guide/animations/animation_enter_leave.gif" alt="Enter and leave animations" align="right" style="width:250px;"></img>
</figure>
@ -258,7 +258,7 @@ entering and leaving of elements:
* Enter: `void => *`
* Leave: `* => void`
For example, in the `animations` array below there are two transitions that use
For example, in the `animations` array below there are two transitions that use
the `void => *` and `* => void` syntax to animate the element in and out of the view.
<code-example path="animations/src/app/hero-list-enter-leave.component.ts" region="animationdef" title="hero-list-enter-leave.component.ts (excerpt)" linenums="false">
@ -294,7 +294,7 @@ These two common animations have their own aliases:
## Example: Entering and leaving from different states
<figure>
<img src="assets/images/guide/animations/animation_enter_leave_states.gif" alt="Enter and leave animations combined with state animations" align="right" style="width:200px"></img>
<img src="content/images/guide/animations/animation_enter_leave_states.gif" alt="Enter and leave animations combined with state animations" align="right" style="width:200px"></img>
</figure>
@ -313,7 +313,7 @@ This gives you fine-grained control over each transition:
<figure class='image-display'>
<img src="assets/images/guide/animations/ng_animate_transitions_inactive_active_void.png" alt="This example transitions between active, inactive, and void states" width="400"></img>
<img src="content/images/guide/animations/ng_animate_transitions_inactive_active_void.png" alt="This example transitions between active, inactive, and void states" width="400"></img>
</figure>
@ -346,7 +346,7 @@ If you don't provide a unit when specifying dimension, Angular assumes the defau
## Automatic property calculation
<figure>
<img src="assets/images/guide/animations/animation_auto.gif" alt="Animation with automated height calculation" align="right" style="width:220px;margin-left:20px"></img>
<img src="content/images/guide/animations/animation_auto.gif" alt="Animation with automated height calculation" align="right" style="width:220px;margin-left:20px"></img>
</figure>
@ -405,7 +405,7 @@ and the delay (or as the *second* value when there is no delay):
<figure>
<img src="assets/images/guide/animations/animation_timings.gif" alt="Animations with specific timings" align="right" style="width:220px;margin-left:20px"></img>
<img src="content/images/guide/animations/animation_timings.gif" alt="Animations with specific timings" align="right" style="width:220px;margin-left:20px"></img>
</figure>
@ -427,7 +427,7 @@ slight delay of 10 milliseconds as specified in `'0.2s 10 ease-out'`:
## Multi-step animations with keyframes
<figure>
<img src="assets/images/guide/animations/animation_multistep.gif" alt="Animations with some bounce implemented with keyframes" align="right" style="width:220px;margin-left:20px"></img>
<img src="content/images/guide/animations/animation_multistep.gif" alt="Animations with some bounce implemented with keyframes" align="right" style="width:220px;margin-left:20px"></img>
</figure>
@ -461,7 +461,7 @@ offsets receive offsets `0`, `0.5`, and `1`.
## Parallel animation groups
<figure>
<img src="assets/images/guide/animations/animation_groups.gif" alt="Parallel animations with different timings, implemented with groups" align="right" style="width:220px;margin-left:20px"></img>
<img src="content/images/guide/animations/animation_groups.gif" alt="Parallel animations with different timings, implemented with groups" align="right" style="width:220px;margin-left:20px"></img>
</figure>
@ -501,7 +501,7 @@ those callbacks like this:
The callbacks receive an `AnimationEvent` that contains contains useful properties such as
The callbacks receive an `AnimationEvent` that contains contains useful properties such as
`fromState`, `toState` and `totalTime`.
Those callbacks will fire whether or not an animation is picked up.
Those callbacks will fire whether or not an animation is picked up.

View File

@ -297,8 +297,8 @@ The _RxJs_ Observable library is an essential Angular dependency published as an
Luckily, there is a Rollup plugin that modifies _RxJs_
to use the ES `import` and `export` statements that Rollup requires.
Rollup then preserves the parts of `RxJS` referenced by the application
in the final bundle. Using it is straigthforward. Add the following to
Rollup then preserves the parts of `RxJS` referenced by the application
in the final bundle. Using it is straigthforward. Add the following to
the `plugins` array in `rollup-config.js`:
<code-example path="aot-compiler/rollup-config.js" region="commonjs" title="rollup-config.js (CommonJs to ES2015 Plugin)" linenums="false">
@ -307,7 +307,7 @@ the `plugins` array in `rollup-config.js`:
*Minification*
Rollup tree shaking reduces code size considerably. Minification makes it smaller still.
This cookbook relies on the _uglify_ Rollup plugin to minify and mangle the code.
This cookbook relies on the _uglify_ Rollup plugin to minify and mangle the code.
Add the following to the `plugins` array:
<code-example path="aot-compiler/rollup-config.js" region="uglify" title="rollup-config.js (CommonJs to ES2015 Plugin)" linenums="false">
@ -317,7 +317,7 @@ Add the following to the `plugins` array:
In a production setting, you would also enable gzip on the web server to compress
the code into an even smaller package going over the wire.
</div>
{@a run-rollup}
@ -602,8 +602,8 @@ showing exactly which application and Angular modules and classes are included i
Here's the map for _Tour of Heroes_.
<a href="assets/images/guide/aot-compiler/toh-pt6-bundle.png" title="View larger image">
<a href="content/images/guide/aot-compiler/toh-pt6-bundle.png" title="View larger image">
<figure class='image-display'>
<img src="assets/images/guide/aot-compiler/toh-pt6-bundle.png" alt="toh-pt6-bundle"></img>
<img src="content/images/guide/aot-compiler/toh-pt6-bundle.png" alt="toh-pt6-bundle"></img>
</figure>
</a>

View File

@ -27,7 +27,7 @@ You'll learn the details in the pages that follow. For now, focus on the big pic
<figure>
<img src="assets/images/guide/architecture/overview2.png" alt="overview" style="margin-left:-40px;" width="700"></img>
<img src="content/images/guide/architecture/overview2.png" alt="overview" style="margin-left:-40px;" width="700"></img>
</figure>
@ -64,23 +64,23 @@ Learn these building blocks, and you're on your way.
## Modules
<figure>
<img src="assets/images/guide/architecture/module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/architecture/module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px"></img>
</figure>
Angular apps are modular and Angular has its own modularity system called _Angular modules_ or _NgModules_.
_Angular modules_ are a big deal.
_Angular modules_ are a big deal.
This page introduces modules; the [Angular modules](guide/ngmodule) page covers them in depth.
<br class="l-clear-both"><br>
Every Angular app has at least one Angular module class, [the _root module_](guide/appmodule "AppModule: the root module"),
Every Angular app has at least one Angular module class, [the _root module_](guide/appmodule "AppModule: the root module"),
conventionally named `AppModule`.
While the _root module_ may be the only module in a small application, most apps have many more
While the _root module_ may be the only module in a small application, most apps have many more
_feature modules_, each a cohesive block of code dedicated to an application domain,
a workflow, or a closely related set of capabilities.
a workflow, or a closely related set of capabilities.
An Angular module, whether a _root_ or _feature_, is a class with an `@NgModule` decorator.
@ -98,7 +98,7 @@ Learn more</a> about decorators on the web.
`NgModule` is a decorator function that takes a single metadata object whose properties describe the module.
`NgModule` is a decorator function that takes a single metadata object whose properties describe the module.
The most important properties are:
* `declarations` - the _view classes_ that belong to this module.
Angular has three kinds of view classes: [components](guide/architecture#components), [directives](guide/architecture#directives), and [pipes](guide/pipes).
@ -110,7 +110,7 @@ Angular has three kinds of view classes: [components](guide/architecture#compone
* `providers` - creators of [services](guide/architecture#services) that this module contributes to
the global collection of services; they become accessible in all parts of the app.
* `bootstrap` - the main application view, called the _root component_,
* `bootstrap` - the main application view, called the _root component_,
that hosts all other app views. Only the _root module_ should set this `bootstrap` property.
Here's a simple root module:
@ -125,15 +125,15 @@ Here's a simple root module:
The `export` of `AppComponent` is just to show how to export; it isn't actually necessary in this example. A root module has no reason to _export_ anything because other components don't need to _import_ the root module.
The `export` of `AppComponent` is just to show how to export; it isn't actually necessary in this example. A root module has no reason to _export_ anything because other components don't need to _import_ the root module.
</div>
Launch an application by _bootstrapping_ its root module.
Launch an application by _bootstrapping_ its root module.
During development you're likely to bootstrap the `AppModule` in a `main.ts` file like this one.
<code-example path="architecture/src/main.ts" title="src/main.ts" linenums="false">
@ -149,7 +149,7 @@ JavaScript also has its own module system for managing collections of JavaScript
It's completely different and unrelated to the Angular module system.
In JavaScript each _file_ is a module and all objects defined in the file belong to that module.
The module declares some objects to be public by marking them with the `export` key word.
The module declares some objects to be public by marking them with the `export` key word.
Other JavaScript modules use *import statements* to access public objects from other modules.
@ -182,12 +182,12 @@ These are two different and _complementary_ module systems. Use them both to wri
<figure>
<img src="assets/images/guide/architecture/library-module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/architecture/library-module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px"></img>
</figure>
Angular ships as a collection of JavaScript modules. You can think of them as library modules.
Angular ships as a collection of JavaScript modules. You can think of them as library modules.
Each Angular library name begins with the `@angular` prefix.
@ -244,7 +244,7 @@ Learn more from the [Angular modules](guide/ngmodule) page.
<figure>
<img src="assets/images/guide/architecture/hero-component.png" alt="Component" align="left" style="width:200px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/architecture/hero-component.png" alt="Component" align="left" style="width:200px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -284,7 +284,7 @@ Your app can take action at each moment in this lifecycle through optional [life
## Templates
<figure>
<img src="assets/images/guide/architecture/template.png" alt="Template" align="left" style="width:200px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/architecture/template.png" alt="Template" align="left" style="width:200px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -314,7 +314,7 @@ The `HeroDetailComponent` is a **child** of the `HeroListComponent`.
<figure>
<img src="assets/images/guide/architecture/component-tree.png" alt="Metadata" align="left" style="width:300px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/architecture/component-tree.png" alt="Metadata" align="left" style="width:300px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -330,7 +330,7 @@ Notice how `<hero-detail>` rests comfortably among native HTML elements. Custom
## Metadata
<figure>
<img src="assets/images/guide/architecture/metadata.png" alt="Metadata" align="left" style="width:150px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/architecture/metadata.png" alt="Metadata" align="left" style="width:150px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -375,11 +375,11 @@ Angular inserts an instance of the `HeroListComponent` view between those tags.
* `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`
so it can get the list of heroes to display.
so it can get the list of heroes to display.
<figure>
<img src="assets/images/guide/architecture/template-metadata-component.png" alt="Metadata" align="left" style="height:200px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/architecture/template-metadata-component.png" alt="Metadata" align="left" style="height:200px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -406,7 +406,7 @@ into actions and value updates. Writing such push/pull logic by hand is tedious,
read as any experienced jQuery programmer can attest.
<figure>
<img src="assets/images/guide/architecture/databinding.png" alt="Data Binding" style="width:220px; float:left; margin-left:-40px;margin-right:20px"></img>
<img src="content/images/guide/architecture/databinding.png" alt="Data Binding" style="width:220px; float:left; margin-left:-40px;margin-right:20px"></img>
</figure>
@ -454,7 +454,7 @@ from the root of the application component tree through all child components.
<figure>
<img src="assets/images/guide/architecture/component-databinding.png" alt="Data Binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/architecture/component-databinding.png" alt="Data Binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -463,7 +463,7 @@ Data binding plays an important role in communication
between a template and its component.<br class="l-clear-both">
<figure>
<img src="assets/images/guide/architecture/parent-child-binding.png" alt="Parent/Child binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/architecture/parent-child-binding.png" alt="Parent/Child binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -478,7 +478,7 @@ Data binding is also important for communication between parent and child compon
## Directives
<figure>
<img src="assets/images/guide/architecture/directive.png" alt="Parent child" style="float:left; width:150px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/architecture/directive.png" alt="Parent child" style="float:left; width:150px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -556,7 +556,7 @@ Of course, you can also write your own directives. Components such as
## Services
<figure>
<img src="assets/images/guide/architecture/service.png" alt="Service" style="float:left; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/architecture/service.png" alt="Service" style="float:left; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -624,7 +624,7 @@ application logic into services and make those services available to components
## Dependency injection
<figure>
<img src="assets/images/guide/architecture/dependency-injection.png" alt="Service" style="float:left; width:200px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/architecture/dependency-injection.png" alt="Service" style="float:left; width:200px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -656,7 +656,7 @@ This is *dependency injection*.
The process of `HeroService` injection looks a bit like this:
<figure>
<img src="assets/images/guide/architecture/injector-injects.png" alt="Service"></img>
<img src="content/images/guide/architecture/injector-injects.png" alt="Service"></img>
</figure>

View File

@ -39,7 +39,7 @@ Two examples are [NgFor](guide/template-syntax#ngFor) and [NgIf](guide/template-
Learn about them in the [Structural Directives](guide/structural-directives) guide.
*Attribute directives* are used as attributes of elements.
The built-in [NgStyle](guide/template-syntax#ngStyle) directive in the
The built-in [NgStyle](guide/template-syntax#ngStyle) directive in the
[Template Syntax](guide/template-syntax) guide, for example,
can change several element styles at the same time.
@ -108,7 +108,7 @@ they don't conflict with standard HTML attributes.
This also reduces the risk of colliding with third-party directive names.
Make sure you do **not** prefix the `highlight` directive name with **`ng`** because
that prefix is reserved for Angular and using it could cause bugs that are difficult to diagnose.
that prefix is reserved for Angular and using it could cause bugs that are difficult to diagnose.
For a simple demo, the short prefix, `my`, helps distinguish your custom directive.
@ -116,7 +116,7 @@ For a simple demo, the short prefix, `my`, helps distinguish your custom directi
After the `@Directive` metadata comes the directive's controller class,
After the `@Directive` metadata comes the directive's controller class,
called `HighlightDirective`, which contains the logic for the directive.
Exporting `HighlightDirective` makes it accessible to other components.
@ -168,7 +168,7 @@ Now when the app runs, the `myHighlight` directive highlights the paragraph text
<figure class='image-display'>
<img src="assets/images/guide/attribute-directives/first-highlight.png" alt="First Highlight"></img>
<img src="content/images/guide/attribute-directives/first-highlight.png" alt="First Highlight"></img>
</figure>
@ -179,7 +179,7 @@ Now when the app runs, the `myHighlight` directive highlights the paragraph text
### Your directive isn't working?
Did you remember to add the directive to the `declarations` attribute of `@NgModule`?
Did you remember to add the directive to the `declarations` attribute of `@NgModule`?
It is easy to forget!
Open the console in the browser tools and look for an error like this:
@ -236,7 +236,7 @@ each adorned by the `HostListener` decorator.
The `@HostListener` decorator lets you subscribe to events of the DOM
The `@HostListener` decorator lets you subscribe to events of the DOM
element that hosts an attribute directive, the `<p>` in this case.
@ -280,7 +280,7 @@ the mouse hovers over the `p` and disappears as it moves out.
<figure class='image-display'>
<img src="assets/images/guide/attribute-directives/highlight-directive-anim.gif" alt="Second Highlight"></img>
<img src="content/images/guide/attribute-directives/highlight-directive-anim.gif" alt="Second Highlight"></img>
</figure>
@ -438,7 +438,7 @@ Here are the harness and directive in action.
<figure class='image-display'>
<img src="assets/images/guide/attribute-directives/highlight-directive-v2-anim.gif" alt="Highlight v.2"></img>
<img src="content/images/guide/attribute-directives/highlight-directive-v2-anim.gif" alt="Highlight v.2"></img>
</figure>
@ -491,7 +491,7 @@ Here's how the harness should work when you're done coding.
<figure class='image-display'>
<img src="assets/images/guide/attribute-directives/highlight-directive-final-anim.gif" alt="Final Highlight"></img>
<img src="content/images/guide/attribute-directives/highlight-directive-final-anim.gif" alt="Final Highlight"></img>
</figure>
@ -607,4 +607,4 @@ Now apply that reasoning to the following example:
* The `myHighlight` property on the left refers to an _aliased_ property of the `HighlightDirective`,
not a property of the template's component. There are trust issues.
Therefore, the directive property must carry the `@Input` decorator.
Therefore, the directive property must carry the `@Input` decorator.

View File

@ -123,7 +123,7 @@ Your app greets you with a message:
<figure class='image-display'>
<img src='assets/images/guide/cli-quickstart/app-works.png' alt="The app works!"></img>
<img src='content/images/guide/cli-quickstart/app-works.png' alt="The app works!"></img>
</figure>
@ -161,7 +161,7 @@ Open `src/app/app.component.css` and give the component some style.
<figure class='image-display'>
<img src='assets/images/guide/cli-quickstart/my-first-app.png' alt="Output of QuickStart app"></img>
<img src='content/images/guide/cli-quickstart/my-first-app.png' alt="Output of QuickStart app"></img>
</figure>

View File

@ -54,7 +54,7 @@ The running application displays three heroes:
<figure class='image-display'>
<img src="assets/images/guide/component-communication/parent-to-child.png" alt="Parent-to-child"></img>
<img src="content/images/guide/component-communication/parent-to-child.png" alt="Parent-to-child"></img>
</figure>
@ -98,7 +98,7 @@ Here's the `NameParentComponent` demonstrating name variations including a name
<figure class='image-display'>
<img src="assets/images/guide/component-communication/setter.png" alt="Parent-to-child-setter"></img>
<img src="content/images/guide/component-communication/setter.png" alt="Parent-to-child-setter"></img>
</figure>
@ -156,7 +156,7 @@ Here's the output of a button-pushing sequence:
<figure class='image-display'>
<img src="assets/images/guide/component-communication/parent-to-child-on-changes.gif" alt="Parent-to-child-onchanges"></img>
<img src="content/images/guide/component-communication/parent-to-child-on-changes.gif" alt="Parent-to-child-onchanges"></img>
</figure>
@ -210,7 +210,7 @@ and the method processes it:
<figure class='image-display'>
<img src="assets/images/guide/component-communication/child-to-parent.gif" alt="Child-to-parent"></img>
<img src="content/images/guide/component-communication/child-to-parent.gif" alt="Child-to-parent"></img>
</figure>
@ -272,7 +272,7 @@ Here we see the parent and child working together.
<figure class='image-display'>
<img src="assets/images/guide/component-communication/countdown-timer-anim.gif" alt="countdown timer"></img>
<img src="content/images/guide/component-communication/countdown-timer-anim.gif" alt="countdown timer"></img>
</figure>
@ -309,7 +309,7 @@ must read or write child component values or must call child component methods.
When the parent component *class* requires that kind of access,
***inject*** the child component into the parent as a *ViewChild*.
The following example illustrates this technique with the same
The following example illustrates this technique with the same
[Countdown Timer](guide/component-communication#countdown-timer-example) example.
Neither its appearance nor its behavior will change.
The child [CountdownTimerComponent](guide/component-communication#countdown-timer-example) is the same as well.
@ -424,7 +424,7 @@ facilitated by the service:
<figure class='image-display'>
<img src="assets/images/guide/component-communication/bidirectional-service.gif" alt="bidirectional-service"></img>
<img src="content/images/guide/component-communication/bidirectional-service.gif" alt="bidirectional-service"></img>
</figure>
@ -441,4 +441,4 @@ and verify that the history meets expectations:
[Back to top](guide/component-communication#top)
[Back to top](guide/component-communication#top)

View File

@ -171,7 +171,7 @@ Once all the dependencies are in place, the `AppComponent` displays the user inf
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/logged-in-user.png" alt="Logged In User"></img>
<img src="content/images/guide/dependency-injection/logged-in-user.png" alt="Logged In User"></img>
</figure>
@ -337,7 +337,7 @@ Find this example in <live-example name="dependency-injection-in-action">live co
and confirm that the three `HeroBioComponent` instances have their own cached hero data.
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/hero-bios.png" alt="Bios"></img>
<img src="content/images/guide/dependency-injection/hero-bios.png" alt="Bios"></img>
</figure>
@ -403,7 +403,7 @@ placing it in the `<ng-content>` slot of the `HeroBioComponent` template:
It looks like this, with the hero's telephone number from `HeroContactComponent` projected above the hero description:
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/hero-bio-and-content.png" alt="bio and contact"></img>
<img src="content/images/guide/dependency-injection/hero-bio-and-content.png" alt="bio and contact"></img>
</figure>
@ -440,7 +440,7 @@ Thanks to `@Optional()`, Angular sets the `loggerService` to null and the rest o
Here's the `HeroBiosAndContactsComponent` in action.
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/hero-bios-and-contacts.png" alt="Bios with contact into"></img>
<img src="content/images/guide/dependency-injection/hero-bios-and-contacts.png" alt="Bios with contact into"></img>
</figure>
@ -450,7 +450,7 @@ until it finds the logger at the `AppComponent` level. The logger logic kicks in
with the gratuitous "!!!", indicating that the logger was found.
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/hero-bio-contact-no-host.png" alt="Without @Host"></img>
<img src="content/images/guide/dependency-injection/hero-bio-contact-no-host.png" alt="Without @Host"></img>
</figure>
@ -495,7 +495,7 @@ first without a value (yielding the default color) and then with an assigned col
The following image shows the effect of mousing over the `<hero-bios-and-contacts>` tag.
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/highlight.png" alt="Highlighted bios"></img>
<img src="content/images/guide/dependency-injection/highlight.png" alt="Highlighted bios"></img>
</figure>
{@a providers}
@ -570,10 +570,10 @@ But not every dependency can be satisfied by creating a new instance of a class.
You need other ways to deliver dependency values and that means you need other ways to specify a provider.
The `HeroOfTheMonthComponent` example demonstrates many of the alternatives and why you need them.
It's visually simple: a few properties and the logs produced by a logger.
It's visually simple: a few properties and the logs produced by a logger.
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/hero-of-month.png" alt="Hero of the month" width="300px"></img>
<img src="content/images/guide/dependency-injection/hero-of-month.png" alt="Hero of the month" width="300px"></img>
</figure>
@ -595,7 +595,7 @@ The code behind it gives you plenty to think about.
The `provide` object literal takes a *token* and a *definition object*.
The *token* is usually a class but [it doesn't have to be](guide/dependency-injection-in-action#tokens).
The *definition* object has a required property that specifies how to create the singleton instance of the service. In this case, the property.
The *definition* object has a required property that specifies how to create the singleton instance of the service. In this case, the property.
@ -728,7 +728,7 @@ Now put it to use in a simplified version of the `HeroOfTheMonthComponent`.
The `HeroOfTheMonthComponent` constructor's `logger` parameter is typed as `MinimalLogger` so only the `logs` and `logInfo` members are visible in a TypeScript-aware editor:
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/minimal-logger-intellisense.png" alt="MinimalLogger restricted API"></img>
<img src="content/images/guide/dependency-injection/minimal-logger-intellisense.png" alt="MinimalLogger restricted API"></img>
</figure>
@ -743,7 +743,7 @@ Behind the scenes, Angular actually sets the `logger` parameter to the full serv
The following image, which displays the logging date, confirms the point:
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/date-logger-entry.png" alt="DateLoggerService entry" width="300px"></img>
<img src="content/images/guide/dependency-injection/date-logger-entry.png" alt="DateLoggerService entry" width="300px"></img>
</figure>
@ -849,7 +849,7 @@ But *no class* in this application inherits from `MinimalLogger`.
The `LoggerService` and the `DateLoggerService` _could_ have inherited from `MinimalLogger`.
They could have _implemented_ it instead in the manner of an interface.
But they did neither.
But they did neither.
The `MinimalLogger` is used exclusively as a dependency injection token.
When you use a class this way, it's called a ***class-interface***.
@ -941,7 +941,7 @@ to display a *sorted* list of heroes.
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/sorted-heroes.png" alt="Sorted Heroes"></img>
<img src="content/images/guide/dependency-injection/sorted-heroes.png" alt="Sorted Heroes"></img>
</figure>
@ -1003,8 +1003,8 @@ These complications argue for *avoiding component inheritance*.
## Find a parent component by injection
Application components often need to share information.
More loosely coupled techniques such as data binding and service sharing
are preferable. But sometimes it makes sense for one component
More loosely coupled techniques such as data binding and service sharing
are preferable. But sometimes it makes sense for one component
to have a direct reference to another component
perhaps to access values or call methods on that component.
@ -1013,7 +1013,7 @@ Although an Angular application is a tree of components,
there is no public API for inspecting and traversing that tree.
There is an API for acquiring a child reference.
Check out `Query`, `QueryList`, `ViewChildren`, and `ContentChildren`
Check out `Query`, `QueryList`, `ViewChildren`, and `ContentChildren`
in the [API Reference](api/).
There is no public API for acquiring a parent reference.
@ -1050,7 +1050,7 @@ after injecting an `AlexComponent` into her constructor:
Notice that even though the [@Optional](guide/dependency-injection-in-action#optional) qualifier
Notice that even though the [@Optional](guide/dependency-injection-in-action#optional) qualifier
is there for safety,
the <live-example name="dependency-injection-in-action"></live-example>
confirms that the `alex` parameter is set.
@ -1078,8 +1078,8 @@ whose API your `NewsComponent` understands.
Looking for components that implement an interface would be better.
That's not possible because TypeScript interfaces disappear
from the transpiled JavaScript, which doesn't support interfaces.
That's not possible because TypeScript interfaces disappear
from the transpiled JavaScript, which doesn't support interfaces.
There's no artifact to look for.
</div>
@ -1087,7 +1087,7 @@ There's no artifact to look for.
This isn't necessarily good design.
This example is examining *whether a component can
This example is examining *whether a component can
inject its parent via the parent's base class*.
The sample's `CraigComponent` explores this question. [Looking back](guide/dependency-injection-in-action#alex),
@ -1126,7 +1126,7 @@ The parent must cooperate by providing an *alias* to itself in the name of a *cl
Recall that Angular always adds a component instance to its own injector;
that's why you could inject *Alex* into *Cathy* [earlier](guide/dependency-injection-in-action#known-parent).
Write an [*alias provider*](guide/dependency-injection-in-action#useexisting)&mdash;a `provide` object literal with a `useExisting`
Write an [*alias provider*](guide/dependency-injection-in-action#useexisting)&mdash;a `provide` object literal with a `useExisting`
definition&mdash;that creates an *alternative* way to inject the same component instance
and add that provider to the `providers` array of the `@Component` metadata for the `AlexComponent`:
@ -1142,7 +1142,7 @@ and add that provider to the `providers` array of the `@Component` metadata for
[Parent](guide/dependency-injection-in-action#parent-token) is the provider's *class-interface* token.
The [*forwardRef*](guide/dependency-injection-in-action#forwardref) breaks the circular reference you just created by having the `AlexComponent` refer to itself.
*Carol*, the third of *Alex*'s child components, injects the parent into its `parent` parameter,
*Carol*, the third of *Alex*'s child components, injects the parent into its `parent` parameter,
the same way you've done it before:
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="carol-class" title="parent-finder.component.ts (CarolComponent class)" linenums="false">
@ -1154,7 +1154,7 @@ the same way you've done it before:
Here's *Alex* and family in action:
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/alex.png" alt="Alex in action"></img>
<img src="content/images/guide/dependency-injection/alex.png" alt="Alex in action"></img>
</figure>
@ -1215,7 +1215,7 @@ Here's *Alice*, *Barry* and family in action:
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/alice.png" alt="Alice in action"></img>
<img src="content/images/guide/dependency-injection/alice.png" alt="Alice in action"></img>
</figure>

View File

@ -18,7 +18,7 @@ The final UI looks like this:
<figure class='image-display'>
<img src="assets/images/guide/displaying-data/final.png" alt="Final UI"></img>
<img src="content/images/guide/displaying-data/final.png" alt="Final UI"></img>
</figure>
@ -126,7 +126,7 @@ inside the `<my-app>` tag.
Now run the app. It should display the title and hero name:
<figure class='image-display'>
<img src="assets/images/guide/displaying-data/title-and-hero.png" alt="Title and Hero"></img>
<img src="content/images/guide/displaying-data/title-and-hero.png" alt="Title and Hero"></img>
</figure>
@ -233,7 +233,7 @@ Now the heroes appear in an unordered list.
<figure class='image-display'>
<img src="assets/images/guide/displaying-data/hero-names-list.png" alt="After ngfor"></img>
<img src="content/images/guide/displaying-data/hero-names-list.png" alt="After ngfor"></img>
</figure>

View File

@ -102,8 +102,8 @@ because it doesn't render any additional output.
Take a closer look at the methods in `ad-banner.component.ts`.
`AdBannerComponent` takes an array of `AdItem` objects as input,
which ultimately comes from `AdService`. `AdItem` objects specify
the type of component to load and any data to bind to the
which ultimately comes from `AdService`. `AdItem` objects specify
the type of component to load and any data to bind to the
component.`AdService` returns the actual ads making up the ad campaign.
Passing an array of components to `AdBannerComponent` allows for a
@ -141,17 +141,17 @@ value to select an `adItem` from the array.
After `loadComponent()` selects an ad, it uses `ComponentFactoryResolver`
to resolve a `ComponentFactory` for each specific component.
After `loadComponent()` selects an ad, it uses `ComponentFactoryResolver`
to resolve a `ComponentFactory` for each specific component.
The `ComponentFactory` then creates an instance of each component.
Next, you're targeting the `viewContainerRef` that
exists on this specific instance of the component. How do you know it's
this specific instance? Because it's referring to `adHost` and `adHost` is the
Next, you're targeting the `viewContainerRef` that
exists on this specific instance of the component. How do you know it's
this specific instance? Because it's referring to `adHost` and `adHost` is the
directive you set up earlier to tell Angular where to insert dynamic components.
As you may recall, `AdDirective` injects `ViewContainerRef` into its constructor.
This is how the directive accesses the element that you want to use to host the dynamic component.
As you may recall, `AdDirective` injects `ViewContainerRef` into its constructor.
This is how the directive accesses the element that you want to use to host the dynamic component.
To add the component to the template, you call `createComponent()` on `ViewContainerRef`.
@ -214,9 +214,9 @@ Here are two sample components and the `AdComponent` interface for reference:
The final ad banner looks like this:
<figure class='image-display'>
<img src="assets/images/guide/dynamic-component-loader/ads.gif" alt="Ads"></img>
<img src="content/images/guide/dynamic-component-loader/ads.gif" alt="Ads"></img>
</figure>
See the <live-example name="dynamic-component-loader"></live-example>.
See the <live-example name="dynamic-component-loader"></live-example>.

View File

@ -7,20 +7,20 @@ Render dynamic forms with FormGroup.
@description
Building handcrafted forms can be costly and time-consuming,
Building handcrafted forms can be costly and time-consuming,
especially if you need a great number of them, they're similar to each other, and they change frequently
to meet rapidly changing business and regulatory requirements.
It may be more economical to create the forms dynamically, based on
It may be more economical to create the forms dynamically, based on
metadata that describes the business object model.
This cookbook shows you how to use `formGroup` to dynamically
This cookbook shows you how to use `formGroup` to dynamically
render a simple form with different control types and validation.
It's a primitive start.
It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience.
All such greatness has humble beginnings.
The example in this cookbook is a dynamic form to build an
The example in this cookbook is a dynamic form to build an
online application experience for heroes seeking employment.
The agency is constantly tinkering with the application process.
You can create the forms on the fly *without changing the application code*.
@ -44,8 +44,8 @@ Start by creating an `NgModule` called `AppModule`.
This cookbook uses [reactive forms](guide/reactive-forms).
Reactive forms belongs to a different `NgModule` called `ReactiveFormsModule`,
so in order to access any reactive forms directives, you have to import
Reactive forms belongs to a different `NgModule` called `ReactiveFormsModule`,
so in order to access any reactive forms directives, you have to import
`ReactiveFormsModule` from the `@angular/forms` library.
Bootstrap the `AppModule` in `main.ts`.
@ -81,12 +81,12 @@ The following `QuestionBase` is a fundamental question class.
From this base you can derive two new classes in `TextboxQuestion` and `DropdownQuestion`
From this base you can derive two new classes in `TextboxQuestion` and `DropdownQuestion`
that represent textbox and dropdown questions.
The idea is that the form will be bound to specific question types and render the
The idea is that the form will be bound to specific question types and render the
appropriate controls dynamically.
`TextboxQuestion` supports multiple HTML5 types such as text, email, and url
`TextboxQuestion` supports multiple HTML5 types such as text, email, and url
via the `type` property.
@ -106,7 +106,7 @@ via the `type` property.
Next is `QuestionControlService`, a simple service for transforming the questions to a `FormGroup`.
In a nutshell, the form group consumes the metadata from the question model and
In a nutshell, the form group consumes the metadata from the question model and
allows you to specify default values and validation rules.
@ -117,7 +117,7 @@ allows you to specify default values and validation rules.
{@a form-component}
## Question form components
Now that you have defined the complete model you are ready
Now that you have defined the complete model you are ready
to create components to represent the dynamic form.
@ -139,7 +139,7 @@ to create components to represent the dynamic form.
It presents a list of questions, each bound to a `<df-question>` component element.
The `<df-question>` tag matches the `DynamicFormQuestionComponent`,
the component responsible for rendering the details of each _individual_
the component responsible for rendering the details of each _individual_
question based on values in the data-bound question object.
@ -164,8 +164,8 @@ The `ngSwitch` determines which type of question to display.
In both components you're relying on Angular's **formGroup** to connect the template HTML to the
underlying control objects, populated from the question model with display and validation rules.
`formControlName` and `formGroup` are directives defined in
`ReactiveFormsModule`. The templates can access these directives
`formControlName` and `formGroup` are directives defined in
`ReactiveFormsModule`. The templates can access these directives
directly since you imported `ReactiveFormsModule` from `AppModule`.
{@a questionnaire-data}
@ -176,9 +176,9 @@ directly since you imported `ReactiveFormsModule` from `AppModule`.
The set of questions you've defined for the job application is returned from the `QuestionService`.
In a real app you'd retrieve these questions from storage.
The key point is that you control the hero job application questions
The key point is that you control the hero job application questions
entirely through the objects returned from `QuestionService`.
Questionnaire maintenance is a simple matter of adding, updating,
Questionnaire maintenance is a simple matter of adding, updating,
and removing objects from the `questions` array.
@ -198,7 +198,7 @@ Finally, display an instance of the form in the `AppComponent` shell.
{@a dynamic-template}
## Dynamic Template
Although in this example you're modelling a job application for heroes, there are
Although in this example you're modelling a job application for heroes, there are
no references to any specific hero question
outside the objects returned by `QuestionService`.
@ -217,9 +217,9 @@ Saving and retrieving the data is an exercise for another time.
The final form looks like this:
<figure class='image-display'>
<img src="assets/images/guide/dynamic-form/dynamic-form.png" alt="Dynamic-Form"></img>
<img src="content/images/guide/dynamic-form/dynamic-form.png" alt="Dynamic-Form"></img>
</figure>
[Back to top](guide/dynamic-form#top)
[Back to top](guide/dynamic-form#top)

View File

@ -41,7 +41,7 @@ the form-specific directives and techniques described in this page.
You can also use a reactive (or model-driven) approach to build forms.
You can also use a reactive (or model-driven) approach to build forms.
However, this page focuses on template-driven forms.
@ -60,7 +60,7 @@ You'll learn to build a template-driven form that looks like this:
<figure class='image-display'>
<img src="assets/images/guide/forms/hero-form-1.png" width="400px" alt="Clean Form"></img>
<img src="content/images/guide/forms/hero-form-1.png" width="400px" alt="Clean Form"></img>
</figure>
@ -74,7 +74,7 @@ If you delete the hero name, the form displays a validation error in an attentio
<figure class='image-display'>
<img src="assets/images/guide/forms/hero-form-2.png" width="400px" alt="Invalid, Name Required"></img>
<img src="content/images/guide/forms/hero-form-2.png" width="400px" alt="Invalid, Name Required"></img>
</figure>
@ -148,7 +148,7 @@ You can create a new hero like this:
## Create a form component
An Angular form has two parts: an HTML-based _template_ and a component _class_
An Angular form has two parts: an HTML-based _template_ and a component _class_
to handle data and user interactions programmatically.
Begin with the class because it states, in brief, what the hero editor can do.
@ -301,7 +301,7 @@ You added a *Submit* button at the bottom with some classes on it for styling.
In template driven forms, if you've imported `FormsModule`, you don't have to do anything
In template driven forms, if you've imported `FormsModule`, you don't have to do anything
to the `<form>` tag in order to make use of `FormsModule`. Continue on to see how this works.
@ -372,7 +372,7 @@ Running the app right now would be disappointing.
<figure class='image-display'>
<img src="assets/images/guide/forms/hero-form-3.png" width="400px" alt="Early form with no binding"></img>
<img src="content/images/guide/forms/hero-form-3.png" width="400px" alt="Early form with no binding"></img>
</figure>
@ -413,8 +413,8 @@ You left yourself a note to throw it away when you're done.
Focus on the binding syntax: `[(ngModel)]="..."`.
You need one more addition to display the data. Declare
a template variable for the form. Update the `<form>` tag with
You need one more addition to display the data. Declare
a template variable for the form. Update the `<form>` tag with
`#heroForm="ngForm"` as follows:
@ -456,7 +456,7 @@ At some point it might look like this:
<figure class='image-display'>
<img src="assets/images/guide/forms/ng-model-in-action.png" width="400px" alt="ngModel in action"></img>
<img src="content/images/guide/forms/ng-model-in-action.png" width="400px" alt="ngModel in action"></img>
</figure>
@ -529,7 +529,7 @@ If you run the app now and change every hero model property, the form might disp
<figure class='image-display'>
<img src="assets/images/guide/forms/ng-model-in-action-2.png" width="400px" alt="ngModel in action"></img>
<img src="content/images/guide/forms/ng-model-in-action-2.png" width="400px" alt="ngModel in action"></img>
</figure>
@ -642,7 +642,7 @@ The actions and effects are as follows:
<figure class='image-display'>
<img src="assets/images/guide/forms/control-state-transitions-anim.gif" alt="Control State Transition"></img>
<img src="content/images/guide/forms/control-state-transitions-anim.gif" alt="Control State Transition"></img>
</figure>
@ -651,7 +651,7 @@ You should see the following transitions and class names:
<figure class='image-display'>
<img src="assets/images/guide/forms/ng-control-class-changes.png" width="500px" alt="Control state transitions"></img>
<img src="content/images/guide/forms/ng-control-class-changes.png" width="500px" alt="Control state transitions"></img>
</figure>
@ -671,7 +671,7 @@ on the left of the input box:
<figure class='image-display'>
<img src="assets/images/guide/forms/validity-required-indicator.png" width="400px" alt="Invalid Form"></img>
<img src="content/images/guide/forms/validity-required-indicator.png" width="400px" alt="Invalid Form"></img>
</figure>
@ -705,7 +705,7 @@ When the user deletes the name, the form should look like this:
<figure class='image-display'>
<img src="assets/images/guide/forms/name-required-error.png" width="400px" alt="Name required"></img>
<img src="content/images/guide/forms/name-required-error.png" width="400px" alt="Name required"></img>
</figure>
@ -833,8 +833,8 @@ to the hero form component's `onSubmit()` method:
You'd already defined a template reference variable,
`#heroForm`, and initialized it with the value "ngForm".
You'd already defined a template reference variable,
`#heroForm`, and initialized it with the value "ngForm".
Now, use that variable to access the form with the Submit button.
@ -849,7 +849,7 @@ using an event binding. Here's the code:
If you run the application now, you find that the button is enabled&mdash;although
If you run the application now, you find that the button is enabled&mdash;although
it doesn't do anything useful yet.
Now if you delete the Name, you violate the "required" rule, which

View File

@ -55,7 +55,7 @@ open simultaneously.
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/component-hierarchy.png" alt="injector tree" width="600"></img>
<img src="content/images/guide/dependency-injection/component-hierarchy.png" alt="injector tree" width="600"></img>
</figure>
@ -149,7 +149,7 @@ Each tax return component has the following characteristics:
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/hid-heroes-anim.gif" width="400" alt="Heroes in action"></img>
<img src="content/images/guide/dependency-injection/hid-heroes-anim.gif" width="400" alt="Heroes in action"></img>
</figure>
@ -234,7 +234,7 @@ Component (B) is the parent of another component (C) that defines its own, even
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/car-components.png" alt="car components" width="220"></img>
<img src="content/images/guide/dependency-injection/car-components.png" alt="car components" width="220"></img>
</figure>
@ -247,7 +247,7 @@ its injector produces an instance of `Car` resolved by injector (C) with an `Eng
<figure class='image-display'>
<img src="assets/images/guide/dependency-injection/injector-tree.png" alt="car injector tree" width="600"></img>
<img src="content/images/guide/dependency-injection/injector-tree.png" alt="car injector tree" width="600"></img>
</figure>

View File

@ -178,7 +178,7 @@ The app uses the Angular <code>Http</code> client to communicate via **XMLHttpRe
It works like this:
<figure class='image-display'>
<img src='assets/images/guide/http/http-toh.gif' alt="ToH mini app" width="250"></img>
<img src='content/images/guide/http/http-toh.gif' alt="ToH mini app" width="250"></img>
</figure>
@ -333,13 +333,13 @@ and `map()` is one of the RxJS *operators*.
## RxJS library
<a href="http://reactivex.io/rxjs" title="RxJS Reactive Extensions">RxJS</a>
is a third party library, endorsed by Angular, that implements the
is a third party library, endorsed by Angular, that implements the
<a href="https://www.youtube.com/watch?v=VLGCCpOWFFw" title="Video: Rob Wormald on Observables"><b>asynchronous Observable</b></a> pattern.
All of the Developer Guide samples have installed the RxJS npm package
because Observables are used widely in Angular applications.
_This_ app needs it when working with the HTTP client.
But you must take a critical extra step to make RxJS Observables usable:
But you must take a critical extra step to make RxJS Observables usable:
_you must import the RxJS operators individually_.
### Enable RxJS operators
@ -646,8 +646,8 @@ highlighting just the parts that are different.
You can follow the Promise `then(this.extractData).catch(this.handleError)` pattern as in
this example.
Alternatively, you can call `toPromise(success, fail)`. The Observable's `map` callback moves to the
first *success* parameter and its `catch` callback to the second *fail* parameter
Alternatively, you can call `toPromise(success, fail)`. The Observable's `map` callback moves to the
first *success* parameter and its `catch` callback to the second *fail* parameter
in this pattern: `.toPromise(this.extractData, this.handleError)`.
The `errorHandler` forwards an error message as a failed `Promise` instead of a failed `Observable`.
@ -680,15 +680,15 @@ Both methods take the same functional arguments.
The less obvious but critical difference is that these two methods return very different results.
The Promise-based `then()` returns another Promise. You can keep chaining
The Promise-based `then()` returns another Promise. You can keep chaining
more `then()` and `catch()` calls, getting a new promise each time.
The `subscribe()` method returns a `Subscription`. A `Subscription` is not another `Observable`.
It's the end of the line for Observables. You can't call `map()` on it or call `subscribe()` again.
The `Subscription` object has a different purpose, signified by its primary method, `unsubscribe`.
To understand the implications and consequences of subscriptions,
watch [Ben Lesh's talk on Observables](https://www.youtube.com/watch?v=3LKMwkuK0ZE)
To understand the implications and consequences of subscriptions,
watch [Ben Lesh's talk on Observables](https://www.youtube.com/watch?v=3LKMwkuK0ZE)
or his video course on [egghead.io](https://egghead.io/lessons/rxjs-rxjs-observables-vs-promises).
@ -746,7 +746,7 @@ types in a text box:
<figure class='image-display'>
<img src='assets/images/guide/http/wiki-1.gif' alt="Wikipedia search app (v.1)" width="250"></img>
<img src='content/images/guide/http/wiki-1.gif' alt="Wikipedia search app (v.1)" width="250"></img>
</figure>
@ -831,7 +831,7 @@ turn your attention to the component (template and class) that takes user input
The template presents an `<input>` element *search box* to gather search terms from the user,
and calls a `search(term)` method after each `keyup` event.
The component's `search(term)` method delegates to the `WikipediaService`, which returns an
The component's `search(term)` method delegates to the `WikipediaService`, which returns an
Observable array of string results (`Observable<string[]>`).
Instead of subscribing to the Observable inside the component, as in the `HeroListComponent`,
the app forwards the Observable result to the template (via `items`) where the `async` pipe
@ -865,7 +865,7 @@ It should only make requests when the user *stops typing*.
Here's how it will work after refactoring:
<figure class='image-display'>
<img src='assets/images/guide/http/wiki-2.gif' alt="Wikipedia search app (v.2)" width="250"></img>
<img src='content/images/guide/http/wiki-2.gif' alt="Wikipedia search app (v.2)" width="250"></img>
</figure>

View File

@ -9,7 +9,7 @@ Angular calls lifecycle hook methods on directives and components as it creates,
<figure>
<img src="assets/images/guide/lifecycle-hooks/hooks-in-sequence.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:30px"></img>
<img src="content/images/guide/lifecycle-hooks/hooks-in-sequence.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:30px"></img>
</figure>
@ -262,7 +262,7 @@ calls the lifecycle hook methods in the following sequence at specific moments:
{@a interface-optional}
## Interfaces are optional (technically)
@ -465,7 +465,7 @@ The peek-a-boo exists to show how Angular calls the hooks in the expected order.
This snapshot reflects the state of the log after the user clicked the *Create...* button and then the *Destroy...* button.
<figure class='image-display'>
<img src="assets/images/guide/lifecycle-hooks/peek-a-boo.png" alt="Peek-a-boo"></img>
<img src="content/images/guide/lifecycle-hooks/peek-a-boo.png" alt="Peek-a-boo"></img>
</figure>
@ -549,7 +549,7 @@ with an entry in the *Hook Log* as seen here:
<figure class='image-display'>
<img src='assets/images/guide/lifecycle-hooks/spy-directive.gif' alt="Spy Directive"></img>
<img src='content/images/guide/lifecycle-hooks/spy-directive.gif' alt="Spy Directive"></img>
</figure>
@ -672,7 +672,7 @@ Here's the sample in action as the user makes changes.
<figure class='image-display'>
<img src='assets/images/guide/lifecycle-hooks/on-changes-anim.gif' alt="OnChanges"></img>
<img src='content/images/guide/lifecycle-hooks/on-changes-anim.gif' alt="OnChanges"></img>
</figure>
@ -718,7 +718,7 @@ so you can see how often `DoCheck` is called. The results are illuminating:
<figure class='image-display'>
<img src='assets/images/guide/lifecycle-hooks/do-check-anim.gif' alt="DoCheck"></img>
<img src='content/images/guide/lifecycle-hooks/do-check-anim.gif' alt="DoCheck"></img>
</figure>
@ -788,14 +788,14 @@ Angular's unidirectional data flow rule forbids updates to the view *after* it h
Both of these hooks fire _after_ the component's view has been composed.
Angular throws an error if the hook updates the component's data-bound `comment` property immediately (try it!).
The `LoggerService.tick_then()` postpones the log update
The `LoggerService.tick_then()` postpones the log update
for one turn of the browser's JavaScript cycle and that's just long enough.
Here's *AfterView* in action:
<figure class='image-display'>
<img src='assets/images/guide/lifecycle-hooks/after-view-anim.gif' alt="AfterView"></img>
<img src='content/images/guide/lifecycle-hooks/after-view-anim.gif' alt="AfterView"></img>
</figure>
@ -859,7 +859,7 @@ It tells Angular where to insert that content.
In this case, the projected content is the `<my-child>` from the parent.
<figure class='image-display'>
<img src='assets/images/guide/lifecycle-hooks/projected-child-view.png' width="230" alt="Projected Content"></img>
<img src='content/images/guide/lifecycle-hooks/projected-child-view.png' width="230" alt="Projected Content"></img>
</figure>
@ -915,4 +915,4 @@ There's no [need to wait](guide/lifecycle-hooks#wait-a-tick).
Recall that Angular calls both *AfterContent* hooks before calling either of the *AfterView* hooks.
Angular completes composition of the projected content *before* finishing the composition of this component's view.
There is a small window between the `AfterContent...` and `AfterView...` hooks to modify the host view.
There is a small window between the `AfterContent...` and `AfterView...` hooks to modify the host view.

View File

@ -145,7 +145,7 @@ As you click the button, the displayed date alternates between
<figure class='image-display'>
<img src='assets/images/guide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle"></img>
<img src='content/images/guide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle"></img>
</figure>
@ -237,7 +237,7 @@ Now you need a component to demonstrate the pipe.
<figure class='image-display'>
<img src='assets/images/guide/pipes/power-booster.png' alt="Power Booster"></img>
<img src='content/images/guide/pipes/power-booster.png' alt="Power Booster"></img>
</figure>
@ -285,7 +285,7 @@ your pipe and two-way data binding with `ngModel`.
<figure class='image-display'>
<img src='assets/images/guide/pipes/power-boost-calculator-anim.gif' alt="Power Boost Calculator"></img>
<img src='content/images/guide/pipes/power-boost-calculator-anim.gif' alt="Power Boost Calculator"></img>
</figure>
@ -372,7 +372,7 @@ code with checkbox switches and additional displays to help you experience these
<figure class='image-display'>
<img src='assets/images/guide/pipes/flying-heroes-anim.gif' alt="Flying Heroes"></img>
<img src='content/images/guide/pipes/flying-heroes-anim.gif' alt="Flying Heroes"></img>
</figure>
@ -559,7 +559,7 @@ The component renders as the following:
<figure class='image-display'>
<img src='assets/images/guide/pipes/hero-list.png' alt="Hero List"></img>
<img src='content/images/guide/pipes/hero-list.png' alt="Hero List"></img>
</figure>
@ -674,4 +674,4 @@ Any capabilities that you would have put in a pipe and shared across the app can
written in a filtering/sorting service and injected into the component.
If these performance and minification considerations don't apply to you, you can always create your own such pipes
(similar to the [FlyingHeroesPipe](guide/pipes#impure-flying-heroes)) or find them in the community.
(similar to the [FlyingHeroesPipe](guide/pipes#impure-flying-heroes)) or find them in the community.

View File

@ -53,57 +53,57 @@ But they diverge markedly in philosophy, programming style, and technique.
They even have their own modules: the `ReactiveFormsModule` and the `FormsModule`.
### _Reactive_ forms
Angular _reactive_ forms facilitate a _reactive style_ of programming
Angular _reactive_ forms facilitate a _reactive style_ of programming
that favors explicit management of the data flowing between
a non-UI _data model_ (typically retrieved from a server) and a
UI-oriented _form model_ that retains the states
and values of the HTML controls on screen. Reactive forms offer the ease
a non-UI _data model_ (typically retrieved from a server) and a
UI-oriented _form model_ that retains the states
and values of the HTML controls on screen. Reactive forms offer the ease
of using reactive patterns, testing, and validation.
With _reactive_ forms, you create a tree of Angular form control objects
in the component class and bind them to native form control elements in the
component template, using techniques described in this guide.
in the component class and bind them to native form control elements in the
component template, using techniques described in this guide.
You create and manipulate form control objects directly in the
component class. As the component class has immediate access to both the data
model and the form control structure, you can push data model values into
the form controls and pull user-changed values back out. The component can
You create and manipulate form control objects directly in the
component class. As the component class has immediate access to both the data
model and the form control structure, you can push data model values into
the form controls and pull user-changed values back out. The component can
observe changes in form control state and react to those changes.
One advantage of working with form control objects directly is that value and validity updates
are [always synchronous and under your control](guide/reactive-forms#async-vs-sync "Async vs sync").
One advantage of working with form control objects directly is that value and validity updates
are [always synchronous and under your control](guide/reactive-forms#async-vs-sync "Async vs sync").
You won't encounter the timing issues that sometimes plague a template-driven form
and reactive forms can be easier to unit test.
In keeping with the reactive paradigm, the component
In keeping with the reactive paradigm, the component
preserves the immutability of the _data model_,
treating it as a pure source of original values.
Rather than update the data model directly,
the component extracts user changes and forwards them to an external component or service,
which does something with them (such as saving them)
and returns a new _data model_ to the component that reflects the updated model state.
Using reactive form directives does not require you to follow all reactive priniciples,
Rather than update the data model directly,
the component extracts user changes and forwards them to an external component or service,
which does something with them (such as saving them)
and returns a new _data model_ to the component that reflects the updated model state.
Using reactive form directives does not require you to follow all reactive priniciples,
but it does facilitate the reactive programming approach should you choose to use it.
### _Template-driven_ forms
_Template-driven_ forms, introduced in the [Template guide](guide/forms), take a completely different approach.
You place HTML form controls (such as `<input>` and `<select>`) in the component template and
bind them to _data model_ properties in the component, using directives
You place HTML form controls (such as `<input>` and `<select>`) in the component template and
bind them to _data model_ properties in the component, using directives
like `ngModel`.
You don't create Angular form control objects. Angular directives
create them for you, using the information in your data bindings.
You don't create Angular form control objects. Angular directives
create them for you, using the information in your data bindings.
You don't push and pull data values. Angular handles that for you with `ngModel`.
Angular updates the mutable _data model_ with user changes as they happen.
For this reason, the `ngModel` directive is not part of the ReactiveFormsModule.
While this means less code in the component class,
While this means less code in the component class,
[template-driven forms are asynchronous](guide/reactive-forms#async-vs-sync "Async vs sync")
which may complicate development in more advanced scenarios.
which may complicate development in more advanced scenarios.
{@a async-vs-sync}
@ -113,37 +113,37 @@ which may complicate development in more advanced scenarios.
Reactive forms are synchronous. Template-driven forms are asynchronous. It's a difference that matters.
In reactive forms, you create the entire form control tree in code.
You can immediately update a value or drill down through the descendents of the parent form
In reactive forms, you create the entire form control tree in code.
You can immediately update a value or drill down through the descendents of the parent form
because all controls are always available.
Template-driven forms delegate creation of their form controls to directives.
To avoid "_changed after checked_" errors,
To avoid "_changed after checked_" errors,
these directives take more than one cycle to build the entire control tree.
That means you must wait a tick before manipulating any of the controls
from within the component class.
For example, if you inject the form control with a `@ViewChild(NgForm)` query and examine it in the
For example, if you inject the form control with a `@ViewChild(NgForm)` query and examine it in the
[`ngAfterViewInit` lifecycle hook](guide/lifecycle-hooks#afterview "Lifecycle hooks guide: AfterView"),
you'll discover that it has no children.
You must wait a tick, using `setTimeout`, before you can
extract a value from a control, test its validity, or set it to a new value.
The asynchrony of template-driven forms also complicates unit testing.
You must wrap your test block in `async()` or `fakeAsync()` to
avoid looking for values in the form that aren't there yet.
The asynchrony of template-driven forms also complicates unit testing.
You must wrap your test block in `async()` or `fakeAsync()` to
avoid looking for values in the form that aren't there yet.
With reactive forms, everything is available when you expect it to be.
### Which is better, reactive or template-driven?
### Which is better, reactive or template-driven?
Neither is "better".
They're two different architectural paradigms,
They're two different architectural paradigms,
with their own strengths and weaknesses.
Choose the approach that works best for you.
You may decide to use both in the same application.
The balance of this _reactive forms_ guide explores the _reactive_ paradigm and
concentrates exclusively on reactive forms techniques.
The balance of this _reactive forms_ guide explores the _reactive_ paradigm and
concentrates exclusively on reactive forms techniques.
For information on _template-driven forms_, see the [_Forms_](guide/forms) guide.
In the next section, you'll set up your project for the reactive form demo.
@ -156,7 +156,7 @@ Then you'll learn about the [Angular form classes](guide/reactive-forms#essentia
## Setup
Follow the steps in the [_Setup_ guide](guide/setup "Setup guide")
Follow the steps in the [_Setup_ guide](guide/setup "Setup guide")
for creating a new project folder (perhaps called `reactive-forms`)
based on the _QuickStart seed_.
@ -177,9 +177,9 @@ Create a new `data-model.ts` file in the `app` directory and copy the content be
The file exports two classes and two constants. The `Address`
and `Hero` classes define the application _data model_.
The `heroes` and `states` constants supply the test data.
The file exports two classes and two constants. The `Address`
and `Hero` classes define the application _data model_.
The `heroes` and `states` constants supply the test data.
@ -187,7 +187,7 @@ The `heroes` and `states` constants supply the test data.
## Create a _reactive forms_ component
Make a new file called
Make a new file called
`hero-detail.component.ts` in the `app` directory and import these symbols:
@ -206,8 +206,8 @@ Now enter the `@Component` decorator that specifies the `HeroDetailComponent` me
Next, create an exported `HeroDetailComponent` class with a `FormControl`.
`FormControl` is a directive that allows you to create and manage
Next, create an exported `HeroDetailComponent` class with a `FormControl`.
`FormControl` is a directive that allows you to create and manage
a `FormControl` instance directly.
@ -218,14 +218,14 @@ a `FormControl` instance directly.
Here you are creating a `FormControl` called `name`.
It will be bound in the template to an HTML `input` box for the hero name.
Here you are creating a `FormControl` called `name`.
It will be bound in the template to an HTML `input` box for the hero name.
A `FormControl` constructor accepts three, optional arguments:
A `FormControl` constructor accepts three, optional arguments:
the initial data value, an array of validators, and an array of async validators.
This simple control doesn't have data or validators.
In real apps, most form controls have both.
In real apps, most form controls have both.
<div class="l-sub-section">
@ -255,9 +255,9 @@ Now create the component's template, `src/app/hero-detail.component.html`, with
To let Angular know that this is the input that you want to
associate to the `name` `FormControl` in the class,
you need `[formControl]="name"` in the template on the `<input>`.
To let Angular know that this is the input that you want to
associate to the `name` `FormControl` in the class,
you need `[formControl]="name"` in the template on the `<input>`.
@ -265,7 +265,7 @@ you need `[formControl]="name"` in the template on the `<input>`.
Disregard the `form-control` _CSS_ class. It belongs to the
Disregard the `form-control` _CSS_ class. It belongs to the
<a href="http://getbootstrap.com/" title="Bootstrap CSS">Bootstrap CSS library</a>,
not Angular.
It _styles_ the form but in no way impacts the logic of the form.
@ -280,13 +280,13 @@ It _styles_ the form but in no way impacts the logic of the form.
## Import the _ReactiveFormsModule_
The HeroDetailComponent template uses `formControlName`
The HeroDetailComponent template uses `formControlName`
directive from the `ReactiveFormsModule`.
In this sample, you declare the `HeroDetailComponent` in the `AppModule`.
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`.
1. Add `ReactiveFormsModule` to the `AppModule`'s `imports` list.
1. Add `HeroDetailComponent` to the declarations array.
@ -318,11 +318,11 @@ Revise the `AppComponent` template so it displays the `HeroDetailComponent`.
It may be helpful to read a brief description of the core form classes.
* [_AbstractControl_](api/forms/index/AbstractControl-class "API Reference: AbstractControl")
is the abstract base class for the three concrete form control classes:
is the abstract base class for the three concrete form control classes:
`FormControl`, `FormGroup`, and `FormArray`.
It provides their common behaviors and properties, some of which are _observable_.
* [_FormControl_](api/forms/index/FormControl-class "API Reference: FormControl")
* [_FormControl_](api/forms/index/FormControl-class "API Reference: FormControl")
tracks the value and validity status of an _individual_ form control.
It corresponds to an HTML form control such as an input box or selector.
@ -349,11 +349,11 @@ Add the `bootstrap` _CSS stylesheet_ to the head of `index.html`:
Now that everything is wired up, the browser should display something like this:
Now that everything is wired up, the browser should display something like this:
<figure class='image-display'>
<img src="assets/images/guide/reactive-forms/just-formcontrol.png" width="400px" alt="Single FormControl"></img>
<img src="content/images/guide/reactive-forms/just-formcontrol.png" width="400px" alt="Single FormControl"></img>
</figure>
@ -362,9 +362,9 @@ Now that everything is wired up, the browser should display something like this:
## Add a FormGroup
Usually, if you have multiple *FormControls*, you'll want to register
Usually, if you have multiple *FormControls*, you'll want to register
them within a parent `FormGroup`.
This is simple to do. To add a `FormGroup`, add it to the imports section
This is simple to do. To add a `FormGroup`, add it to the imports section
of `hero-detail.component.ts`:
@ -383,7 +383,7 @@ In the class, wrap the `FormControl` in a `FormGroup` called `heroForm` as follo
Now that you've made changes in the class, they need to be reflected in the
Now that you've made changes in the class, they need to be reflected in the
template. Update `hero-detail.component.html` by replacing it with the following.
@ -393,26 +393,26 @@ template. Update `hero-detail.component.html` by replacing it with the following
Notice that now the single input is in a `form` element. The `novalidate`
attribute in the `<form>` element prevents the browser
from attempting native HTML validations.
Notice that now the single input is in a `form` element. The `novalidate`
attribute in the `<form>` element prevents the browser
from attempting native HTML validations.
`formGroup` is a reactive form directive that takes an existing
`FormGroup` instance and associates it with an HTML element.
In this case, it associates the `FormGroup` you saved as
`formGroup` is a reactive form directive that takes an existing
`FormGroup` instance and associates it with an HTML element.
In this case, it associates the `FormGroup` you saved as
`heroForm` with the form element.
Because the class now has a `FormGroup`, you must update the template
syntax for associating the input with the corresponding
`FormControl` in the component class.
Without a parent `FormGroup`,
`[formControl]="name"` worked earlier because that directive
can stand alone, that is, it works without being in a `FormGroup`.
With a parent `FormGroup`, the `name` input needs the syntax
`formControlName=name` in order to be associated
with the correct `FormControl`
in the class. This syntax tells Angular to look for the parent
`FormGroup`, in this case `heroForm`, and then _inside_ that group
Because the class now has a `FormGroup`, you must update the template
syntax for associating the input with the corresponding
`FormControl` in the component class.
Without a parent `FormGroup`,
`[formControl]="name"` worked earlier because that directive
can stand alone, that is, it works without being in a `FormGroup`.
With a parent `FormGroup`, the `name` input needs the syntax
`formControlName=name` in order to be associated
with the correct `FormControl`
in the class. This syntax tells Angular to look for the parent
`FormGroup`, in this case `heroForm`, and then _inside_ that group
to look for a `FormControl` called `name`.
@ -420,10 +420,10 @@ to look for a `FormControl` called `name`.
Disregard the `form-group` _CSS_ class. It belongs to the
Disregard the `form-group` _CSS_ class. It belongs to the
<a href="http://getbootstrap.com/" title="Bootstrap CSS">Bootstrap CSS library</a>,
not Angular.
Like the `form-control` class, it _styles_ the form
Like the `form-control` class, it _styles_ the form
but in no way impacts its logic.
@ -432,8 +432,8 @@ but in no way impacts its logic.
The form looks great. But does it work?
When the user enters a name, where does the value go?
The form looks great. But does it work?
When the user enters a name, where does the value go?
{@a json}
@ -442,7 +442,7 @@ When the user enters a name, where does the value go?
## Taking a look at the form model
The value goes into the **_form model_** that backs the group's `FormControls`.
To see the form model, add the following line after the
To see the form model, add the following line after the
closing `form` tag in the `hero-detail.component.html`:
@ -457,20 +457,20 @@ Piping it through the `JsonPipe` renders the model as JSON in the browser:
<figure class='image-display'>
<img src="assets/images/guide/reactive-forms/json-output.png" width="400px" alt="JSON output"></img>
<img src="content/images/guide/reactive-forms/json-output.png" width="400px" alt="JSON output"></img>
</figure>
The initial `name` property value is the empty string.
The initial `name` property value is the empty string.
Type into the _name_ input box and watch the keystokes appear in the JSON.
Great! You have the basics of a form.
Great! You have the basics of a form.
In real life apps, forms get big fast.
In real life apps, forms get big fast.
`FormBuilder` makes form development and maintenance easier.
@ -481,8 +481,8 @@ In real life apps, forms get big fast.
## Introduction to _FormBuilder_
The `FormBuilder` class helps reduce repetition and
clutter by handling details of control creation for you.
The `FormBuilder` class helps reduce repetition and
clutter by handling details of control creation for you.
To use `FormBuilder`, you need to import it into `hero-detail.component.ts`:
@ -509,7 +509,7 @@ The revised `HeroDetailComponent` looks like this:
`FormBuilder.group` is a factory method that creates a `FormGroup`. &nbsp;
`FormBuilder.group` takes an object whose keys and values are `FormControl` names and their definitions.
`FormBuilder.group` takes an object whose keys and values are `FormControl` names and their definitions.
In this example, the `name` control is defined by its initial data value, an empty string.
Defining a group of controls in a single object makes for a compact, readable style.
@ -520,8 +520,8 @@ It beats writing an equivalent series of `new FormControl(...)` statements.
### Validators.required
Though this guide doesn't go deeply into validations, here is one example that
demonstrates the simplicity of using `Validators.required` in reactive forms.
Though this guide doesn't go deeply into validations, here is one example that
demonstrates the simplicity of using `Validators.required` in reactive forms.
First, import the `Validators` symbol.
@ -531,8 +531,8 @@ First, import the `Validators` symbol.
To make the `name` `FormControl` required, replace the `name`
property in the `FormGroup` with an array.
To make the `name` `FormControl` required, replace the `name`
property in the `FormGroup` with an array.
The first item is the initial value for `name`;
the second is the required validator, `Validators.required`.
@ -548,7 +548,7 @@ the second is the required validator, `Validators.required`.
Reactive validators are simple, composable functions.
Configuring validation is harder in template-driven forms where you must wrap validators in a directive.
Configuring validation is harder in template-driven forms where you must wrap validators in a directive.
</div>
@ -567,29 +567,29 @@ The browser displays the following:
<figure class='image-display'>
<img src="assets/images/guide/reactive-forms/validators-json-output.png" width="400px" alt="Single FormControl"></img>
<img src="content/images/guide/reactive-forms/validators-json-output.png" width="400px" alt="Single FormControl"></img>
</figure>
`Validators.required` is working. The status is `INVALID` because the input box has no value.
Type into the input box to see the status change from `INVALID` to `VALID`.
Type into the input box to see the status change from `INVALID` to `VALID`.
In a real app, you'd replace the diagnosic message with a user-friendly experience.
Using `Validators.required` is optional for the rest of the guide.
Using `Validators.required` is optional for the rest of the guide.
It remains in each of the following examples with the same configuration.
For more on validating Angular forms, see the
[Form Validation](cookbook/form-validation) guide.
[Form Validation](cookbook/form-validation) guide.
### More FormControls
A hero has more than a name.
A hero has an address, a super power and sometimes a sidekick too.
A hero has more than a name.
A hero has an address, a super power and sometimes a sidekick too.
The address has a state property. The user will select a state with a `<select>` box and you'll populate
The address has a state property. The user will select a state with a `<select>` box and you'll populate
the `<option>` elements with states. So import `states` from `data-model.ts`.
<code-example path="reactive-forms/src/app/hero-detail-4.component.ts" region="imports" title="src/app/hero-detail.component.ts (excerpt)" linenums="false">
@ -598,7 +598,7 @@ the `<option>` elements with states. So import `states` from `data-model.ts`.
Declare the `states` property and add some address `FormControls` to the `heroForm` as follows.
Declare the `states` property and add some address `FormControls` to the `heroForm` as follows.
<code-example path="reactive-forms/src/app/hero-detail-4.component.ts" region="v4" title="src/app/hero-detail.component.ts (excerpt)" linenums="false">
@ -607,7 +607,7 @@ Declare the `states` property and add some address `FormControls` to the `heroFo
Then add corresponding markup in `hero-detail.component.html`
Then add corresponding markup in `hero-detail.component.html`
within the `form` element.
@ -621,11 +621,11 @@ within the `form` element.
*Reminder*: Ignore the many mentions of `form-group`,
*Reminder*: Ignore the many mentions of `form-group`,
`form-control`, `center-block`, and `checkbox` in this markup.
Those are _bootstrap_ CSS classes that Angular itself ignores.
Pay attention to the `formGroupName` and `formControlName` attributes.
They are the Angular directives that bind the HTML controls to the
They are the Angular directives that bind the HTML controls to the
Angular `FormGroup` and `FormControl` properties in the component class.
@ -633,19 +633,19 @@ Angular `FormGroup` and `FormControl` properties in the component class.
The revised template includes more text inputs, a select box for the `state`, radio buttons for the `power`,
and a checkbox for the `sidekick`.
The revised template includes more text inputs, a select box for the `state`, radio buttons for the `power`,
and a checkbox for the `sidekick`.
You must bind the option's value property with `[value]="state"`.
You must bind the option's value property with `[value]="state"`.
If you do not bind the value, the select shows the first option from the data model.
The component _class_ defines control properties without regard for their representation in the template.
You define the `state`, `power`, and `sidekick` controls the same way you defined the `name` control.
You tie these controls to the template HTML elements in the same way,
specifiying the `FormControl` name with the `formControlName` directive.
You tie these controls to the template HTML elements in the same way,
specifiying the `FormControl` name with the `formControlName` directive.
See the API reference for more information about
[radio buttons](api/forms/index/RadioControlValueAccessor-directive "API: RadioControlValueAccessor"),
See the API reference for more information about
[radio buttons](api/forms/index/RadioControlValueAccessor-directive "API: RadioControlValueAccessor"),
[selects](api/forms/index/SelectControlValueAccessor-directive "API: SelectControlValueAccessor"), and
[checkboxes](api/forms/index/CheckboxControlValueAccessor-directive "API: CheckboxControlValueAccessor").
@ -656,12 +656,12 @@ See the API reference for more information about
### Nested FormGroups
This form is getting big and unwieldy. You can group some of the related `FormControls`
into a nested `FormGroup`. The `street`, `city`, `state`, and `zip` are properties
This form is getting big and unwieldy. You can group some of the related `FormControls`
into a nested `FormGroup`. The `street`, `city`, `state`, and `zip` are properties
that would make a good _address_ `FormGroup`.
Nesting groups and controls in this way allows you to
mirror the hierarchical structure of the data model
and helps track validation and state for related sets of controls.
Nesting groups and controls in this way allows you to
mirror the hierarchical structure of the data model
and helps track validation and state for related sets of controls.
You used the `FormBuilder` to create one `FormGroup` in this component called `heroForm`.
Let that be the parent `FormGroup`.
@ -674,14 +674,14 @@ assign the result to a new `address` property of the parent `FormGroup`.
Youve changed the structure of the form controls in the component class;
Youve changed the structure of the form controls in the component class;
you must make corresponding adjustments to the component template.
In `hero-detail.component.html`, wrap the address-related `FormControls` in a `div`.
Add a `formGroupName` directive to the `div` and bind it to `"address"`.
That's the property of the _address_ child `FormGroup` within the parent `FormGroup` called `heroForm`.
To make this change visually obvious, slip in an `<h4>` header near the top with the text, _Secret Lair_.
To make this change visually obvious, slip in an `<h4>` header near the top with the text, _Secret Lair_.
The new _address_ HTML looks like this:
@ -692,16 +692,16 @@ The new _address_ HTML looks like this:
After these changes, the JSON output in the browser shows the revised _form model_
with the nested address `FormGroup`:
with the nested address `FormGroup`:
<figure class='image-display'>
<img src="assets/images/guide/reactive-forms/address-group.png" width="400px" alt="JSON output"></img>
<img src="content/images/guide/reactive-forms/address-group.png" width="400px" alt="JSON output"></img>
</figure>
Great! Youve made a group and you can see that the template
Great! Youve made a group and you can see that the template
and the form model are talking to one another.
@ -714,9 +714,9 @@ At the moment, you're dumping the entire form model onto the page.
Sometimes you're interested only in the state of one particular `FormControl`.
You can inspect an individual `FormControl` within a form by extracting it with the `.get()` method.
You can do this _within_ the component class or display it on the
page by adding the following to the template,
immediately after the `{{form.value | json}}` interpolation as follows:
You can do this _within_ the component class or display it on the
page by adding the following to the template,
immediately after the `{{form.value | json}}` interpolation as follows:
<code-example path="reactive-forms/src/app/hero-detail-5.component.html" region="inspect-value" title="src/app/hero-detail.component.html" linenums="false">
@ -734,7 +734,7 @@ To get the state of a `FormControl` thats inside a `FormGroup`, use dot notat
You can use this technique to display _any_ property of a `FormControl`
You can use this technique to display _any_ property of a `FormControl`
such as one of the following:
<style>
@ -788,7 +788,7 @@ such as one of the following:
<td>
the validity of a `FormControl`. Possible values: `VALID`,
the validity of a `FormControl`. Possible values: `VALID`,
`INVALID`, `PENDING`, or `DISABLED`.
</td>
@ -820,7 +820,7 @@ such as one of the following:
`true` if the control user has not yet entered the HTML control
and triggered its blur event. Its opposite is `myControl.touched`.
</td>
</tr>
@ -829,13 +829,13 @@ such as one of the following:
Learn about other `FormControl` properties in the
Learn about other `FormControl` properties in the
[_AbstractControl_](api/forms/index/AbstractControl-class) API reference.
One common reason for inspecting `FormControl` properties is to
make sure the user entered valid values.
Read more about validating Angular forms in the
[Form Validation](cookbook/form-validation) guide.
One common reason for inspecting `FormControl` properties is to
make sure the user entered valid values.
Read more about validating Angular forms in the
[Form Validation](cookbook/form-validation) guide.
@ -856,7 +856,7 @@ The `FormControl` structure is the **_form model_**.
The component must copy the hero values in the _data model_ into the _form model_.
There are two important implications:
1. The developer must understand how the properties of the _data model_
1. The developer must understand how the properties of the _data model_
map to the properties of the _form model_.
2. User changes flow from the DOM elements to the _form model_, not to the _data model_.
@ -917,8 +917,8 @@ Also be sure to update the import from `data-model` so you can reference the `He
## Populate the form model with _setValue_ and _patchValue_
Previously you created a control and initialized its value at the same time.
You can also initialize or reset the values _later_ with the
Previously you created a control and initialized its value at the same time.
You can also initialize or reset the values _later_ with the
`setValue` and `patchValue` methods.
### _setValue_
@ -934,13 +934,13 @@ by passing in a data object whose properties exactly match the _form model_ behi
The `setValue` method checks the data object thoroughly before assigning any form control values.
It will not accept a data object that doesn't match the FormGroup structure or is
missing values for any control in the group. This way, it can return helpful
error messages if you have a typo or if you've nested controls incorrectly.
It will not accept a data object that doesn't match the FormGroup structure or is
missing values for any control in the group. This way, it can return helpful
error messages if you have a typo or if you've nested controls incorrectly.
`patchValue` will fail silently.
On the other hand,`setValue` will catch
the error and report it clearly.
On the other hand,`setValue` will catch
the error and report it clearly.
Notice that you can _almost_ use the entire `hero` as the argument to `setValue`
because its shape is similar to the component's `FormGroup` structure.
@ -956,7 +956,7 @@ This explains the conditional setting of the `address` property in the data obje
### _patchValue_
With **`patchValue`**, you can assign values to specific controls in a `FormGroup`
by supplying an object of key/value pairs for just the controls of interest.
by supplying an object of key/value pairs for just the controls of interest.
This example sets only the form's `name` control.
@ -967,7 +967,7 @@ This example sets only the form's `name` control.
With **`patchValue`** you have more flexibility to cope with wildly divergent data and form models.
But unlike `setValue`, `patchValue` cannot check for missing control
But unlike `setValue`, `patchValue` cannot check for missing control
values and does not throw helpful errors.
### When to set form model values (_ngOnChanges_)
@ -987,7 +987,7 @@ by binding to its `hero` input property.
In this approach, the value of `hero` in the `HeroDetailComponent` changes
In this approach, the value of `hero` in the `HeroDetailComponent` changes
every time the user selects a new hero.
You should call _setValue_ in the [ngOnChanges](guide/lifecycle-hooks#onchanges)
hook, which Angular calls whenever the input `hero` property changes
@ -1021,8 +1021,8 @@ Add the `ngOnChanges` method to the class as follows:
### _reset_ the form flags
You should reset the form when the hero changes so that
control values from the previous hero are cleared and
You should reset the form when the hero changes so that
control values from the previous hero are cleared and
status flags are restored to the _pristine_ state.
You could call `reset` at the top of `ngOnChanges` like this.
@ -1032,8 +1032,8 @@ You could call `reset` at the top of `ngOnChanges` like this.
The `reset` method has an optional `state` value so you can reset the flags _and_ the control values at the same.
Internally, `reset` passes the argument to `setValue`.
The `reset` method has an optional `state` value so you can reset the flags _and_ the control values at the same.
Internally, `reset` passes the argument to `setValue`.
A little refactoring and `ngOnChanges` becomes this:
<code-example path="reactive-forms/src/app/hero-detail-7.component.ts" region="ngOnChanges" title="src/app/hero-detail.component.ts (ngOnchanges - revised)" linenums="false">
@ -1052,16 +1052,16 @@ Together they look a bit like this:
<figure class='image-display'>
<img src="assets/images/guide/reactive-forms/hero-list.png" width="420px" alt="HeroListComponent"></img>
<img src="content/images/guide/reactive-forms/hero-list.png" width="420px" alt="HeroListComponent"></img>
</figure>
The `HeroListComponent` uses an injected `HeroService` to retrieve heroes from the server
and then presents those heroes to the user as a series of buttons.
The `HeroService` emulates an HTTP service.
It returns an `Observable` of heroes that resolves after a short delay,
both to simulate network latency and to indicate visually
The `HeroService` emulates an HTTP service.
It returns an `Observable` of heroes that resolves after a short delay,
both to simulate network latency and to indicate visually
the necessarily asynchronous nature of the application.
When the user clicks on a hero,
@ -1076,11 +1076,11 @@ The remaining `HeroListComponent` and `HeroService` implementation details are n
The techniques involved are covered elsewhere in the documentation, including the _Tour of Heroes_
[here](tutorial/toh-pt3 "ToH: Multiple Components") and [here](tutorial/toh-pt4 "ToH: Services").
If you're coding along with the steps in this reactive forms tutorial,
create the pertinent files based on the
[source code displayed below](guide/reactive-forms#source-code "Reactive Forms source code").
If you're coding along with the steps in this reactive forms tutorial,
create the pertinent files based on the
[source code displayed below](guide/reactive-forms#source-code "Reactive Forms source code").
Notice that `hero-list.component.ts` imports `Observable` and `finally` while `hero.service.ts` imports `Observable`, `of`,
and `delay` from `rxjs`.
and `delay` from `rxjs`.
Then return here to learn about _form array_ properties.
@ -1116,7 +1116,7 @@ In this guide, you define a `FormArray` for `Hero.addresses` and
let the user add or modify addresses (removing addresses is your homework).
Youll need to redefine the form model in the `HeroDetailComponent` constructor,
which currently only displays the first hero address in an _address_ `FormGroup`.
which currently only displays the first hero address in an _address_ `FormGroup`.
<code-example path="reactive-forms/src/app/hero-detail-7.component.ts" region="address-form-group" title="src/app/hero-detail-7.component.ts" linenums="false">
@ -1143,7 +1143,7 @@ Replace the _address_ `FormGroup` definition with a _secretLairs_ `FormArray` de
Changing the form control name from `address` to `secretLairs` drives home an important point:
the _form model_ doesn't have to match the _data model_.
Obviously there has to be a relationship between the two.
Obviously there has to be a relationship between the two.
But it can be anything that makes sense within the application domain.
_Presentation_ requirements often differ from _data_ requirements.
@ -1187,21 +1187,21 @@ Wrap the expression in a `secretLairs` convenience property for clarity and re-u
### Display the _FormArray_
### Display the _FormArray_
The current HTML template displays a single _address_ `FormGroup`.
Revise it to display zero, one, or more of the hero's _address_ `FormGroups`.
This is mostly a matter of wrapping the previous template HTML for an address in a `<div>` and
This is mostly a matter of wrapping the previous template HTML for an address in a `<div>` and
repeating that `<div>` with `*ngFor`.
The trick lies in knowing how to write the `*ngFor`. There are three key points:
1. Add another wrapping `<div>`, around the `<div>` with `*ngFor`, and
1. Add another wrapping `<div>`, around the `<div>` with `*ngFor`, and
set its `formArrayName` directive to `"secretLairs"`.
This step establishes the _secretLairs_ `FormArray` as the context for form controls in the inner, repeated HTML template.
This step establishes the _secretLairs_ `FormArray` as the context for form controls in the inner, repeated HTML template.
1. The source of the repeated items is the `FormArray.controls`, not the `FormArray` itself.
1. The source of the repeated items is the `FormArray.controls`, not the `FormArray` itself.
Each control is an _address_ `FormGroup`, exactly what the previous (now repeated) template HTML expected.
1. Each repeated `FormGroup` needs a unique `formGroupName` which must be the index of the `FormGroup` in the `FormArray`.
@ -1225,7 +1225,7 @@ Here's the complete template for the _secret lairs_ section:
### Add a new lair to the _FormArray_
Add an `addLair` method that gets the _secretLairs_ `FormArray` and appends a new _address_ `FormGroup` to it.
Add an `addLair` method that gets the _secretLairs_ `FormArray` and appends a new _address_ `FormGroup` to it.
<code-example path="reactive-forms/src/app/hero-detail-8.component.ts" region="add-lair" title="src/app/hero-detail.component.ts (addLair method)" linenums="false">
@ -1246,7 +1246,7 @@ Place a button on the form so the user can add a new _secret lair_ and wire it t
Be sure to **add the `type="button"` attribute**.
Be sure to **add the `type="button"` attribute**.
In fact, you should always specify a button's `type`.
Without an explict type, the button type defaults to "submit".
When you later add a _form submit_ action, every "submit" button triggers the submit action which
@ -1265,12 +1265,12 @@ Back in the browser, select the hero named "Magneta".
<figure class='image-display'>
<img src="assets/images/guide/reactive-forms/addresses-array.png" width="400px" alt="JSON output of addresses array"></img>
<img src="content/images/guide/reactive-forms/addresses-array.png" width="400px" alt="JSON output of addresses array"></img>
</figure>
Click the "_Add a Secret Lair_" button.
Click the "_Add a Secret Lair_" button.
A new address section appears. Well done!
### Remove a lair
@ -1289,7 +1289,7 @@ Angular calls `ngOnChanges` when the user picks a hero in the parent `HeroListCo
Picking a hero changes the `HeroDetailComponent.hero` input property.
Angular does _not_ call `ngOnChanges` when the user modifies the hero's _name_ or _secret lairs_.
Fortunately, you can learn about such changes by subscribing to one of the form control properties
Fortunately, you can learn about such changes by subscribing to one of the form control properties
that raises a change event.
These are properties, such as `valueChanges`, that return an RxJS `Observable`.
@ -1326,7 +1326,7 @@ You should see a new name in the log after each keystroke.
### When to use it
An interpolation binding is the easier way to _display_ a name change.
Subscribing to an observable form control property is handy for triggering
Subscribing to an observable form control property is handy for triggering
application logic _within_ the component class.
@ -1343,7 +1343,7 @@ After you implement both features in this section, the form will look like this:
<figure class='image-display'>
<img src="assets/images/guide/reactive-forms/save-revert-buttons.png" width="389px" alt="Form with save & revert buttons"></img>
<img src="content/images/guide/reactive-forms/save-revert-buttons.png" width="389px" alt="Form with save & revert buttons"></img>
</figure>
@ -1361,7 +1361,7 @@ to a save method on the injected `HeroService`.
This original `hero` had the pre-save values. The user's changes are still in the _form model_.
So you create a new `hero` from a combination of original hero values (the `hero.id`)
and deep copies of the changed form model values, using the `prepareSaveHero` helper.
and deep copies of the changed form model values, using the `prepareSaveHero` helper.
<code-example path="reactive-forms/src/app/hero-detail.component.ts" region="prepare-save-hero" title="src/app/hero-detail.component.ts (prepareSaveHero)" linenums="false">
@ -1377,7 +1377,7 @@ and deep copies of the changed form model values, using the `prepareSaveHero` he
**Address deep copy**
Had you assigned the `formModel.secretLairs` to `saveHero.addresses` (see line commented out),
the addresses in `saveHero.addresses` array would be the same objects
the addresses in `saveHero.addresses` array would be the same objects
as the lairs in the `formModel.secretLairs`.
A user's subsequent changes to a lair street would mutate an address street in the `saveHero`.

File diff suppressed because it is too large Load Diff

View File

@ -85,13 +85,13 @@ attacker-controlled data enters the DOM, expect security vulnerabilities.
### Angulars cross-site scripting security model
To systematically block XSS bugs, Angular treats all values as untrusted by default. When a value
is inserted into the DOM from a template, via property, attribute, style, class binding, or interpolation,
is inserted into the DOM from a template, via property, attribute, style, class binding, or interpolation,
Angular sanitizes and escapes untrusted values.
_Angular templates are the same as executable code_: HTML, attributes, and binding expressions
(but not the values bound) in templates are trusted to be safe. This means that applications must
prevent values that an attacker can control from ever making it into the source code of a
template. Never generate template source code by concatenating user input and templates.
template. Never generate template source code by concatenating user input and templates.
To prevent these vulnerabilities, use
the [offline template compiler](guide/security#offline-template-compiler), also known as _template injection_.
@ -143,7 +143,7 @@ tag but keeps safe content such as the text content of the `<script>` tag and th
<figure class='image-display'>
<img src='assets/images/guide/security/binding-inner-html.png' alt='A screenshot showing interpolated and bound HTML values'></img>
<img src='content/images/guide/security/binding-inner-html.png' alt='A screenshot showing interpolated and bound HTML values'></img>
</figure>
@ -159,7 +159,7 @@ templates where possible.
Content Security Policy (CSP) is a defense-in-depth
technique to prevent XSS. To enable CSP, configure your web server to return an appropriate
`Content-Security-Policy` HTTP header. Read more about content security policy at
`Content-Security-Policy` HTTP header. Read more about content security policy at
[An Introduction to Content Security Policy](http://www.html5rocks.com/en/tutorials/security/content-security-policy/)
on the HTML5Rocks website.
@ -172,15 +172,15 @@ on the HTML5Rocks website.
The offline template compiler prevents a whole class of vulnerabilities called template injection,
and greatly improves application performance. Use the offline template compiler in production
deployments; don't dynamically generate templates. Angular trusts template code, so generating
templates, in particular templates containing user data, circumvents Angular's built-in protections.
For information about dynamically constructing forms in a safe way, see the
templates, in particular templates containing user data, circumvents Angular's built-in protections.
For information about dynamically constructing forms in a safe way, see the
[Dynamic Forms](cookbook/dynamic-form) cookbook page.
### Server-side XSS protection
HTML constructed on the server is vulnerable to injection attacks. Injecting template code into an
Angular application is the same as injecting executable code into the
application: it gives the attacker full control over the application. To prevent this,
application: it gives the attacker full control over the application. To prevent this,
use a templating language that automatically escapes values to prevent XSS vulnerabilities on
the server. Don't generate Angular templates on the server side using a templating language; doing this
carries a high risk of introducing template-injection vulnerabilities.
@ -194,10 +194,10 @@ carries a high risk of introducing template-injection vulnerabilities.
Sometimes applications genuinely need to include executable code, display an `<iframe>` from some
URL, or construct potentially dangerous URLs. To prevent automatic sanitization in any of these
situations, you can tell Angular that you inspected a value, checked how it was generated, and made
sure it will always be secure. But *be careful*. If you trust a value that might be malicious, you
are introducing a security vulnerability into your application. If in doubt, find a professional
URL, or construct potentially dangerous URLs. To prevent automatic sanitization in any of these
situations, you can tell Angular that you inspected a value, checked how it was generated, and made
sure it will always be secure. But *be careful*. If you trust a value that might be malicious, you
are introducing a security vulnerability into your application. If in doubt, find a professional
security reviewer.
To mark a value as trusted, inject `DomSanitizer` and call one of the
@ -232,7 +232,7 @@ this, mark the URL value as a trusted URL using the `bypassSecurityTrustUrl` cal
<figure class='image-display'>
<img src='assets/images/guide/security/bypass-security-component.png' alt='A screenshot showing an alert box created from a trusted URL'></img>
<img src='content/images/guide/security/bypass-security-component.png' alt='A screenshot showing an alert box created from a trusted URL'></img>
</figure>
@ -240,7 +240,7 @@ this, mark the URL value as a trusted URL using the `bypassSecurityTrustUrl` cal
If you need to convert user input into a trusted value, use a
controller method. The following template allows users to enter a YouTube video ID and load the
corresponding video in an `<iframe>`. The `<iframe src>` attribute is a resource URL security
context, because an untrusted source can, for example, smuggle in file downloads that unsuspecting users
context, because an untrusted source can, for example, smuggle in file downloads that unsuspecting users
could execute. So call a method on the controller to construct a trusted video URL, which causes
Angular to allow binding into `<iframe src>`:
@ -265,7 +265,7 @@ Angular to allow binding into `<iframe src>`:
Angular has built-in support to help prevent two common HTTP vulnerabilities, cross-site request
forgery (CSRF or XSRF) and cross-site script inclusion (XSSI). Both of these must be mitigated primarily
forgery (CSRF or XSRF) and cross-site script inclusion (XSSI). Both of these must be mitigated primarily
on the server side, but Angular provides helpers to make integration on the client side easier.
@ -276,8 +276,8 @@ on the server side, but Angular provides helpers to make integration on the clie
In a cross-site request forgery (CSRF or XSRF), an attacker tricks the user into visiting
a different web page (such as `evil.com`) with malignant code that secretly sends a malicious request
to the application's web server (such as `example-bank.com`).
a different web page (such as `evil.com`) with malignant code that secretly sends a malicious request
to the application's web server (such as `example-bank.com`).
Assume the user is logged into the application at `example-bank.com`.
The user opens an email and clicks a link to `evil.com`, which opens in a new tab.
@ -286,11 +286,11 @@ The `evil.com` page immediately sends a malicious request to `example-bank.com`.
Perhaps it's a request to transfer money from the user's account to the attacker's account.
The browser automatically sends the `example-bank.com` cookies (including the authentication cookie) with this request.
If the `example-bank.com` server lacks XSRF protection, it can't tell the difference between a legitimate
If the `example-bank.com` server lacks XSRF protection, it can't tell the difference between a legitimate
request from the application and the forged request from `evil.com`.
To prevent this, the application must ensure that a user request originates from the real
application, not from a different site.
application, not from a different site.
The server and client must cooperate to thwart this attack.
In a common anti-XSRF technique, the application server sends a randomly
@ -298,14 +298,14 @@ generated authentication token in a cookie.
The client code reads the cookie and adds a custom request header with the token in all subsequent requests.
The server compares the received cookie value to the request header value and rejects the request if the values are missing or don't match.
This technique is effective because all browsers implement the _same origin policy_. Only code from the website
This technique is effective because all browsers implement the _same origin policy_. Only code from the website
on which cookies are set can read the cookies from that site and set custom headers on requests to that site.
That means only your application can read this cookie token and set the custom header. The malicious code on `evil.com` can't.
Angular's `http` has built-in support for the client-side half of this technique in its `XSRFStrategy`.
Angular's `http` has built-in support for the client-side half of this technique in its `XSRFStrategy`.
The default `CookieXSRFStrategy` is turned on automatically.
Before sending an HTTP request, the `CookieXSRFStrategy` looks for a cookie called `XSRF-TOKEN` and
sets a header named `X-XSRF-TOKEN` with the value of that cookie.
Before sending an HTTP request, the `CookieXSRFStrategy` looks for a cookie called `XSRF-TOKEN` and
sets a header named `X-XSRF-TOKEN` with the value of that cookie.
The server must do its part by setting the
initial `XSRF-TOKEN` cookie and confirming that each subsequent state-modifying request
@ -336,10 +336,10 @@ Or you can implement and provide an entirely custom `XSRFStrategy`:
For information about CSRF at the Open Web Application Security Project (OWASP), see
<a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29">Cross-Site Request Forgery (CSRF)</a> and
<a href="https://www.owasp.org/index.php/CSRF_Prevention_Cheat_Sheet">Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet</a>.
The Stanford University paper
The Stanford University paper
<a href="https://seclab.stanford.edu/websec/csrf/csrf.pdf">Robust Defenses for Cross-Site Request Forgery</a> is a rich source of detail.
See also Dave Smith's easy-to-understand
See also Dave Smith's easy-to-understand
<a href="https://www.youtube.com/watch?v=9inczw6qtpY" title="Cross Site Request Funkery Securing Your Angular Apps From Evil Doers">talk on XSRF at AngularConnect 2016</a>.

View File

@ -29,7 +29,7 @@ See the <live-example name="set-document-title"></live-example>.
</td>
<td>
<img src='assets/images/plunker/plunker-switch-to-editor-button.png' width="200px" height="70px" alt="pop out the window" align="right"></img> <br></br> <img src='assets/images/plunker/plunker-separate-window-button.png' width="200px" height="47px" alt="pop out the window" align="right"></img>
<img src='content/images/plunker/plunker-switch-to-editor-button.png' width="200px" height="70px" alt="pop out the window" align="right"></img> <br></br> <img src='content/images/plunker/plunker-separate-window-button.png' width="200px" height="47px" alt="pop out the window" align="right"></img>
</td>
</tr>
@ -75,7 +75,7 @@ The [Title](api/platform-browser/index/Title-class) service is a simple class th
for getting and setting the current HTML document title:
* `getTitle() : string`&mdash;Gets the title of the current HTML document.
* `setTitle( newTitle : string )`&mdash;Sets the title of the current HTML document.
* `setTitle( newTitle : string )`&mdash;Sets the title of the current HTML document.
You can inject the `Title` service into the root `AppComponent` and expose a bindable `setTitle` method that calls it:
@ -89,7 +89,7 @@ You can inject the `Title` service into the root `AppComponent` and expose a bin
Bind that method to three anchor tags and voilà!
<figure class='image-display'>
<img src="assets/images/guide/set-document-title/set-title-anim.gif" alt="Set title"></img>
<img src="content/images/guide/set-document-title/set-title-anim.gif" alt="Set title"></img>
</figure>
@ -126,8 +126,8 @@ a location you reserve for configuring the runtime Angular environment.
That's exactly what you're doing.
The `Title` service is part of the Angular *browser platform*.
If you bootstrap your application into a different platform,
you'll have to provide a different `Title` service that understands
you'll have to provide a different `Title` service that understands
the concept of a "document title" for that specific platform.
Ideally, the application itself neither knows nor cares about the runtime environment.
[Back to top](guide/set-document-title#top)
[Back to top](guide/set-document-title#top)

View File

@ -16,7 +16,7 @@ Angular has a powerful template engine that lets us easily manipulate the DOM st
This guide looks at how Angular manipulates the DOM with **structural directives** and
This guide looks at how Angular manipulates the DOM with **structural directives** and
how you can write your own structural directives to do the same thing.
### Table of contents
@ -50,10 +50,10 @@ Structural directives are responsible for HTML layout.
They shape or reshape the DOM's _structure_, typically by adding, removing, or manipulating
elements.
As with other directives, you apply a structural directive to a _host element_.
As with other directives, you apply a structural directive to a _host element_.
The directive then does whatever it's supposed to do with that host element and its descendents.
Structural directives are easy to recognize.
Structural directives are easy to recognize.
An asterisk (*) precedes the directive attribute name as in this example.
@ -69,12 +69,12 @@ You'll learn in this guide that the [asterisk (*) is a convenience notation](gui
and the string is a [_microsyntax_](guide/structural-directives#microsyntax) rather than the usual
[template expression](guide/template-syntax#template-expressions).
Angular desugars this notation into a marked-up `<ng-template>` that surrounds the
host element and its descendents.
host element and its descendents.
Each structural directive does something different with that template.
Three of the common, built-in structural directives&mdash;[NgIf](guide/template-syntax#ngIf),
[NgFor](guide/template-syntax#ngFor), and [NgSwitch...](guide/template-syntax#ngSwitch)&mdash;are
described in the [_Template Syntax_](guide/template-syntax) guide and seen in samples throughout the Angular documentation.
Three of the common, built-in structural directives&mdash;[NgIf](guide/template-syntax#ngIf),
[NgFor](guide/template-syntax#ngFor), and [NgSwitch...](guide/template-syntax#ngSwitch)&mdash;are
described in the [_Template Syntax_](guide/template-syntax) guide and seen in samples throughout the Angular documentation.
Here's an example of them in a template:
@ -100,8 +100,8 @@ and how to [write your own](guide/structural-directives#unless) structural direc
Throughout this guide, you'll see a directive spelled in both _UpperCamelCase_ and _lowerCamelCase_.
Already you've seen `NgIf` and `ngIf`.
There's a reason. `NgIf` refers to the directive _class_;
`ngIf` refers to the directive's _attribute name_.
There's a reason. `NgIf` refers to the directive _class_;
`ngIf` refers to the directive's _attribute name_.
A directive _class_ is spelled in _UpperCamelCase_ (`NgIf`).
A directive's _attribute name_ is spelled in _lowerCamelCase_ (`ngIf`).
@ -122,7 +122,7 @@ There are two other kinds of Angular directives, described extensively elsewhere
(1)&nbsp;components and (2)&nbsp;attribute directives.
A *component* manages a region of HTML in the manner of a native HTML element.
Technically it's a directive with a template.
Technically it's a directive with a template.
An [*attribute* directive](guide/attribute-directives) changes the appearance or behavior
of an element, component, or another directive.
@ -158,12 +158,12 @@ Confirm that fact using browser developer tools to inspect the DOM.
<figure class='image-display'>
<img src='assets/images/guide/structural-directives/element-not-in-dom.png' alt="ngIf=false element not in DOM"></img>
<img src='content/images/guide/structural-directives/element-not-in-dom.png' alt="ngIf=false element not in DOM"></img>
</figure>
The top paragraph is in the DOM. The bottom, disused paragraph is not;
The top paragraph is in the DOM. The bottom, disused paragraph is not;
in its place is a comment about "bindings" (more about that [later](guide/structural-directives#asterisk)).
When the condition is false, `NgIf` removes its host element from the DOM,
@ -182,16 +182,16 @@ A directive could hide the unwanted paragraph instead by setting its `display` s
While invisible, the element remains in the DOM.
While invisible, the element remains in the DOM.
<figure class='image-display'>
<img src='assets/images/guide/structural-directives/element-display-in-dom.png' alt="hidden element still in DOM"></img>
<img src='content/images/guide/structural-directives/element-display-in-dom.png' alt="hidden element still in DOM"></img>
</figure>
The difference between hiding and removing doesn't matter for a simple paragraph.
The difference between hiding and removing doesn't matter for a simple paragraph.
It does matter when the host element is attached to a resource intensive component.
Such a component's behavior continues even when hidden.
The component stays attached to its DOM element. It keeps listening to events.
@ -206,12 +206,12 @@ The component's previous state is preserved and ready to display.
The component doesn't re-initialize&mdash;an operation that could be expensive.
So hiding and showing is sometimes the right thing to do.
But in the absence of a compelling reason to keep them around,
But in the absence of a compelling reason to keep them around,
your preference should be to remove DOM elements that the user can't see
and recover the unused resources with a structural directive like `NgIf` .
**These same considerations apply to every structural directive, whether built-in or custom.**
Before applying a structural directive, you might want to pause for a moment
Before applying a structural directive, you might want to pause for a moment
to consider the consequences of adding and removing elements and of creating and destroying components.
@ -256,17 +256,17 @@ Then it translates the template _attribute_ into a `<ng-template>` _element_, wr
* The `*ngIf` directive moved to the `<ng-template>` element where it became a property binding,`[ngIf]`.
* The rest of the `<div>`, including its class attribute, moved inside the `<ng-template>` element.
None of these forms are actually rendered.
None of these forms are actually rendered.
Only the finished product ends up in the DOM.
<figure class='image-display'>
<img src='assets/images/guide/structural-directives/hero-div-in-dom.png' alt="hero div in DOM"></img>
<img src='content/images/guide/structural-directives/hero-div-in-dom.png' alt="hero div in DOM"></img>
</figure>
Angular consumed the `<ng-template>` content during its actual rendering and
Angular consumed the `<ng-template>` content during its actual rendering and
replaced the `<ng-template>` with a diagnostic comment.
The [`NgFor`](guide/structural-directives#ngFor) and [`NgSwitch...`](guide/structural-directives#ngSwitch) directives follow the same pattern.
@ -279,7 +279,7 @@ The [`NgFor`](guide/structural-directives#ngFor) and [`NgSwitch...`](guide/struc
## Inside _*ngFor_
Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax through
template _attribute_ to `<ng-template>` _element_.
template _attribute_ to `<ng-template>` _element_.
Here's a full-featured application of `NgFor`, written all three ways:
@ -294,15 +294,15 @@ This is manifestly more complicated than `ngIf` and rightly so.
The `NgFor` directive has more features, both required and optional, than the `NgIf` shown in this guide.
At minimum `NgFor` needs a looping variable (`let hero`) and a list (`heroes`).
You enable these features in the string assigned to `ngFor`, which you write in Angular's [microsyntax](guide/structural-directives#microsyntax).
You enable these features in the string assigned to `ngFor`, which you write in Angular's [microsyntax](guide/structural-directives#microsyntax).
<div class="alert is-helpful">
Everything _outside_ the `ngFor` string stays with the host element
(the `<div>`) as it moves inside the `<ng-template>`.
Everything _outside_ the `ngFor` string stays with the host element
(the `<div>`) as it moves inside the `<ng-template>`.
In this example, the `[ngClass]="odd"` stays on the `<div>`.
@ -318,12 +318,12 @@ In this example, the `[ngClass]="odd"` stays on the `<div>`.
The Angular microsyntax lets you configure a directive in a compact, friendly string.
The microsyntax parser translates that string into attributes on the `<ng-template>`:
* The `let` keyword declares a [_template input variable_](guide/structural-directives#template-input-variable)
* The `let` keyword declares a [_template input variable_](guide/structural-directives#template-input-variable)
that you reference within the template. The input variables in this example are `hero`, `i`, and `odd`.
The parser translates `let hero`, `let i`, and `let odd` into variables named,
The parser translates `let hero`, `let i`, and `let odd` into variables named,
`let-hero`, `let-i`, and `let-odd`.
* The microsyntax parser takes `of` and `trackby`, title-cases them (`of` -> `Of`, `trackBy` -> `TrackBy`),
* The microsyntax parser takes `of` and `trackby`, title-cases them (`of` -> `Of`, `trackBy` -> `TrackBy`),
and prefixes them with the directive's attribute name (`ngFor`), yielding the names `ngForOf` and `ngForTrackBy`.
Those are the names of two `NgFor` _input properties_ .
That's how the directive learns that the list is `heroes` and the track-by function is `trackById`.
@ -334,18 +334,18 @@ These properties include `index` and `odd` and a special property named `$implic
* The `let-i` and `let-odd` variables were defined as `let i=index` and `let odd=odd`.
Angular sets them to the current value of the context's `index` and `odd` properties.
* The context property for `let-hero` wasn't specified.
It's intended source is implicit.
* The context property for `let-hero` wasn't specified.
It's intended source is implicit.
Angular sets `let-hero` to the value of the context's `$implicit` property
which `NgFor` has initialized with the hero for the current iteration.
* The [API guide](api/common/index/NgFor-directive "API: NgFor")
* The [API guide](api/common/index/NgFor-directive "API: NgFor")
describes additional `NgFor` directive properties and context properties.
These microsyntax mechanisms are available to you when you write your own structural directives.
Studying the
Studying the
[source code for `NgIf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts "Source: NgIf")
and [`NgFor`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts "Source: NgFor")
and [`NgFor`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts "Source: NgFor")
is a great way to learn more.
@ -362,11 +362,11 @@ A _template input variable_ is a variable whose value you can reference _within_
There are several such variables in this example: `hero`, `i`, and `odd`.
All are preceded by the keyword `let`.
A _template input variable_ is **_not_** the same as a
A _template input variable_ is **_not_** the same as a
[template _reference_ variable](guide/template-syntax#ref-vars),
neither _semantically_ nor _syntactically_.
You declare a template _input_ variable using the `let` keyword (`let hero`).
You declare a template _input_ variable using the `let` keyword (`let hero`).
The variable's scope is limited to a _single instance_ of the repeated template.
You can use the same variable name again in the definition of other structural directives.
@ -385,10 +385,10 @@ variable as the `hero` declared as `#hero`.
Someday you'll want to repeat a block of HTML but only when a particular condition is true.
You'll _try_ to put both an `*ngFor` and an `*ngIf` on the same host element.
Angular won't let you. You may apply only one _structural_ directive to an element.
Angular won't let you. You may apply only one _structural_ directive to an element.
The reason is simplicity. Structural directives can do complex things with the host element and its descendents.
When two directives lay claim to the same host element, which one takes precedence?
When two directives lay claim to the same host element, which one takes precedence?
Which should go first, the `NgIf` or the `NgFor`? Can the `NgIf` cancel the effect of the `NgFor`?
If so (and it seems like it should be so), how should Angular generalize the ability to cancel for other structural directives?
@ -417,12 +417,12 @@ Here's an example.
The switch value assigned to `NgSwitch` (`hero.emotion`) determines which
(if any) of the switch cases are displayed.
`NgSwitch` itself is not a structural directive.
`NgSwitch` itself is not a structural directive.
It's an _attribute_ directive that controls the behavior of the other two switch directives.
That's why you write `[ngSwitch]`, never `*ngSwitch`.
`NgSwitchCase` and `NgSwitchDefault` _are_ structural directives.
You attach them to elements using the asterisk (*) prefix notation.
`NgSwitchCase` and `NgSwitchDefault` _are_ structural directives.
You attach them to elements using the asterisk (*) prefix notation.
An `NgSwitchCase` displays its host element when its value matches the switch value.
The `NgSwitchDefault` displays its host element when no sibling `NgSwitchCase` matches the switch value.
@ -431,7 +431,7 @@ The `NgSwitchDefault` displays its host element when no sibling `NgSwitchCase` m
The element to which you apply a directive is its _host_ element.
The element to which you apply a directive is its _host_ element.
The `<happy-hero>` is the host element for the happy `*ngSwitchCase`.
The `<unknown-hero>` is the host element for the `*ngSwitchDefault`.
@ -440,7 +440,7 @@ The `<unknown-hero>` is the host element for the `*ngSwitchDefault`.
As with other structural directives, the `NgSwitchCase` and `NgSwitchDefault`
As with other structural directives, the `NgSwitchCase` and `NgSwitchDefault`
can be desugared into the template _attribute_ form.
@ -480,7 +480,7 @@ You'll refer to the `<ng-template>` when you [write your own structural directiv
## The *&lt;ng-template&gt;*
The &lt;ng-template&gt; is an Angular element for rendering HTML.
It is never displayed directly.
It is never displayed directly.
In fact, before rendering the view, Angular _replaces_ the `<ng-template>` and its contents with a comment.
If there is no structural directive and you merely wrap some elements in a `<ng-template>`,
@ -498,7 +498,7 @@ Angular erases the middle "Hip!", leaving the cheer a bit less enthusiastic.
<figure class='image-display'>
<img src='assets/images/guide/structural-directives/template-rendering.png' width="350" alt="template tag rendering"></img>
<img src='content/images/guide/structural-directives/template-rendering.png' width="350" alt="template tag rendering"></img>
</figure>
@ -536,11 +536,11 @@ such as a `<div>`, and attach the directive to that wrapper.
Introducing another container element&mdash;typically a `<span>` or `<div>`&mdash;to
group the elements under a single _root_ is usually harmless.
Introducing another container element&mdash;typically a `<span>` or `<div>`&mdash;to
group the elements under a single _root_ is usually harmless.
_Usually_ ... but not _always_.
The grouping element may break the template appearance because CSS styles
The grouping element may break the template appearance because CSS styles
neither expect nor accommodate the new layout.
For example, suppose you have the following paragraph layout.
@ -564,7 +564,7 @@ The constructed paragraph renders strangely.
<figure class='image-display'>
<img src='assets/images/guide/structural-directives/bad-paragraph.png' alt="spanned paragraph with bad style"></img>
<img src='content/images/guide/structural-directives/bad-paragraph.png' alt="spanned paragraph with bad style"></img>
</figure>
@ -572,7 +572,7 @@ The constructed paragraph renders strangely.
The `p span` style, intended for use elsewhere, was inadvertently applied here.
Another problem: some HTML elements require all immediate children to be of a specific type.
For example, the `<select>` element requires `<option>` children.
For example, the `<select>` element requires `<option>` children.
You can't wrap the _options_ in a conditional `<div>` or a `<span>`.
When you try this,
@ -588,7 +588,7 @@ the drop down is empty.
<figure class='image-display'>
<img src='assets/images/guide/structural-directives/bad-select.png' alt="spanned options don't work"></img>
<img src='content/images/guide/structural-directives/bad-select.png' alt="spanned options don't work"></img>
</figure>
@ -598,7 +598,7 @@ The browser won't display an `<option>` within a `<span>`.
### &lt;ng-container&gt; to the rescue
The Angular `<ng-container>` is a grouping element that doesn't interfere with styles or layout
because Angular _doesn't put it in the DOM_.
because Angular _doesn't put it in the DOM_.
Here's the conditional paragraph again, this time using `<ng-container>`.
@ -613,7 +613,7 @@ It renders properly.
<figure class='image-display'>
<img src='assets/images/guide/structural-directives/good-paragraph.png' alt="ngcontainer paragraph with proper style"></img>
<img src='content/images/guide/structural-directives/good-paragraph.png' alt="ngcontainer paragraph with proper style"></img>
</figure>
@ -631,13 +631,13 @@ The drop down works properly.
<figure class='image-display'>
<img src='assets/images/guide/structural-directives/select-ngcontainer-anim.gif' alt="ngcontainer options work properly"></img>
<img src='content/images/guide/structural-directives/select-ngcontainer-anim.gif' alt="ngcontainer options work properly"></img>
</figure>
The `<ng-container>` is a syntax element recognized by the Angular parser.
It's not a directive, component, class, or interface.
It's not a directive, component, class, or interface.
It's more like the curly braces in a JavaScript `if`-block:
@ -646,7 +646,7 @@ It's more like the curly braces in a JavaScript `if`-block:
statement1;
statement2;
statement3;
}
}
</code-example>
@ -709,9 +709,9 @@ Angular's own directives do not.
### _TemplateRef_ and _ViewContainerRef_
A simple structural directive like this one creates an
A simple structural directive like this one creates an
[_embedded view_](api/core/index/EmbeddedViewRef-class "API: EmbeddedViewRef")
from the Angular-generated `<ng-template>` and inserts that view in a
from the Angular-generated `<ng-template>` and inserts that view in a
[_view container_](api/core/index/ViewContainerRef-class "API: ViewContainerRef")
adjacent to the directive's original `<p>` host element.
@ -732,7 +732,7 @@ You inject both in the directive constructor as private variables of the class.
### The _myUnless_ property
The directive consumer expects to bind a true/false condition to `[myUnless]`.
That means the directive needs a `myUnless` property, decorated with `@Input`
That means the directive needs a `myUnless` property, decorated with `@Input`
<div class="l-sub-section">
@ -758,7 +758,7 @@ Because the `myUnless` property does work, it needs a setter.
* If the condition is falsy and the view hasn't been created previously,
tell the _view container_ to create the _embedded view_ from the template.
* If the condition is truthy and the view is currently displayed,
* If the condition is truthy and the view is currently displayed,
clear the container which also destroys the view.
Nobody reads the `myUnless` property so it doesn't need a getter.
@ -788,7 +788,7 @@ When the `condition` is truthy, the top (A) paragraph is removed and the bottom
<figure class='image-display'>
<img src='assets/images/guide/structural-directives/unless-anim.gif' alt="UnlessDirective in action"></img>
<img src='content/images/guide/structural-directives/unless-anim.gif' alt="UnlessDirective in action"></img>
</figure>
@ -799,7 +799,7 @@ When the `condition` is truthy, the top (A) paragraph is removed and the bottom
## Summary
You can both try and download the source code for this guide in the <live-example></live-example>.
You can both try and download the source code for this guide in the <live-example></live-example>.
Here is the source from the `src/app/` folder.

View File

@ -17,10 +17,10 @@ Learn how to write templates that display data and consume user events with the
The Angular application manages what the user sees and can do, achieving this through the interaction of a
The Angular application manages what the user sees and can do, achieving this through the interaction of a
component class instance (the *component*) and its user-facing template.
You may be familiar with the component/template duality from your experience with model-view-controller (MVC) or model-view-viewmodel (MVVM).
You may be familiar with the component/template duality from your experience with model-view-controller (MVC) or model-view-viewmodel (MVVM).
In Angular, the component plays the part of the controller/viewmodel, and the template represents the view.
@ -78,17 +78,17 @@ demonstrates all of the syntax and code snippets described in this guide.
## HTML in templates
HTML is the language of the Angular template.
Almost all HTML syntax is valid template syntax.
The `<script>` element is a notable exception;
Almost all HTML syntax is valid template syntax.
The `<script>` element is a notable exception;
it is forbidden, eliminating the risk of script injection attacks.
In practice, `<script>` is ignored and a warning appears in the browser console.
See the [Security](guide/security) page for details.
Some legal HTML doesn't make much sense in a template.
The `<html>`, `<body>`, and `<base>` elements have no useful role.
Some legal HTML doesn't make much sense in a template.
The `<html>`, `<body>`, and `<base>` elements have no useful role.
Pretty much everything else is fair game.
You can extend the HTML vocabulary of your templates with components and directives that appear as new elements and attributes.
You can extend the HTML vocabulary of your templates with components and directives that appear as new elements and attributes.
In the following sections, you'll learn how to get and set DOM (Document Object Model) values dynamically through data binding.
Begin with the first form of data binding&mdash;interpolation&mdash;to see how much richer template HTML can be.
@ -1067,7 +1067,7 @@ content harmlessly.
<figure class='image-display'>
<img src='assets/images/guide/template-syntax/evil-title.png' alt="evil title made safe" width='500px'></img>
<img src='content/images/guide/template-syntax/evil-title.png' alt="evil title made safe" width='500px'></img>
</figure>
@ -1837,7 +1837,7 @@ Here are all variations in action, including the uppercase version:
<figure class='image-display'>
<img src='assets/images/guide/template-syntax/ng-model-anim.gif' alt="NgModel variations"></img>
<img src='content/images/guide/template-syntax/ng-model-anim.gif' alt="NgModel variations"></img>
</figure>
@ -2132,7 +2132,7 @@ Here is an illustration of the _trackBy_ effect.
<figure class='image-display'>
<img src='assets/images/guide/template-syntax/ng-for-track-by-anim.gif' alt="trackBy"></img>
<img src='content/images/guide/template-syntax/ng-for-track-by-anim.gif' alt="trackBy"></img>
</figure>
@ -2167,7 +2167,7 @@ Angular puts only the *selected* element into the DOM.
<figure class='image-display'>
<img src='assets/images/guide/template-syntax/switch-anim.gif' alt="trackBy"></img>
<img src='content/images/guide/template-syntax/switch-anim.gif' alt="trackBy"></img>
</figure>
@ -2417,7 +2417,7 @@ The terms _input_ and _output_ reflect the perspective of the target directive.
<figure class='image-display'>
<img src='assets/images/guide/template-syntax/input-output.png' alt="Inputs and outputs"></img>
<img src='content/images/guide/template-syntax/input-output.png' alt="Inputs and outputs"></img>
</figure>
@ -2669,5 +2669,5 @@ It works perfectly with long property paths such as `a?.b?.c?.d`.
## Summary
You've completed this survey of template syntax.
You've completed this survey of template syntax.
Now it's time to put that knowledge to work on your own components and directives.

View File

@ -389,7 +389,7 @@ The Angular CLI has different commands to do the same thing. Adjust accordingly.
After a few moments, karma opens a browser and starts writing to the console.
<figure class='image-display'>
<img src='assets/images/guide/testing/karma-browser.png' style="width:400px;" alt="Karma browser"></img>
<img src='content/images/guide/testing/karma-browser.png' style="width:400px;" alt="Karma browser"></img>
</figure>
@ -473,7 +473,7 @@ Debug specs in the browser in the same way that you debug an application.
<figure class='image-display'>
<img src='assets/images/guide/testing/karma-1st-spec-debug.png' style="width:700px;" alt="Karma debugging"></img>
<img src='content/images/guide/testing/karma-1st-spec-debug.png' style="width:700px;" alt="Karma debugging"></img>
</figure>
@ -1914,7 +1914,7 @@ Inspect and download _all_ of the guide's application test code with this <live-
The `HeroDetailComponent` is a simple view with a title, two hero fields, and two buttons.
<figure class='image-display'>
<img src='assets/images/guide/testing/hero-detail.component.png' alt="HeroDetailComponent in action"></img>
<img src='content/images/guide/testing/hero-detail.component.png' alt="HeroDetailComponent in action"></img>
</figure>
@ -2505,7 +2505,7 @@ A better solution is to create an artificial test component that demonstrates al
<figure class='image-display'>
<img src='assets/images/guide/testing/highlight-directive-spec.png' width="200px" alt="HighlightDirective spec in action"></img>
<img src='content/images/guide/testing/highlight-directive-spec.png' width="200px" alt="HighlightDirective spec in action"></img>
</figure>
@ -2847,7 +2847,7 @@ Here's a summary of the stand-alone functions, in order of likely utility:
Simulates the passage of time and the completion of pending asynchronous activities
by flushing both _timer_ and _micro-task_ queues within the _fakeAsync test zone_.
<div class="l-sub-section">
@ -2855,7 +2855,7 @@ Here's a summary of the stand-alone functions, in order of likely utility:
The curious, dedicated reader might enjoy this lengthy blog post,
"<a href="https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/"
>_Tasks, microtasks, queues and schedules_</a>".
>_Tasks, microtasks, queues and schedules_</a>".
</div>
@ -3601,7 +3601,7 @@ Here are the most useful `DebugElement` members for testers, in approximate orde
The immediate `DebugElement` children. Walk the tree by descending through `children`.
<div class="l-sub-section">
@ -3609,7 +3609,7 @@ Here are the most useful `DebugElement` members for testers, in approximate orde
`DebugElement` also has `childNodes`, a list of `DebugNode` objects.
`DebugElement` derives from `DebugNode` objects and there are often
more nodes than elements. Testers can usually ignore plain nodes.
more nodes than elements. Testers can usually ignore plain nodes.
</div>

View File

@ -10,7 +10,7 @@ Incrementally upgrade an AngularJS application to Angular.
_Angular_ is the name for the Angular of today and tomorrow.
_AngularJS_ is the name for all v1.x versions of Angular.
AngularJS apps are great.
AngularJS apps are great.
Always consider the business case before moving to Angular.
An important part of that case is the time and effort to get there.
This guide describes the built-in tools for efficiently migrating AngularJS projects over to the
@ -336,7 +336,7 @@ everything work seamlessly:
<figure class='image-display'>
<img src="assets/images/guide/upgrade/injectors.png" alt="The two injectors in a hybrid application" width="700"></img>
<img src="content/images/guide/upgrade/injectors.png" alt="The two injectors in a hybrid application" width="700"></img>
</figure>
@ -381,7 +381,7 @@ ways:
<figure class='image-display'>
<img src="assets/images/guide/upgrade/dom.png" alt="DOM element ownership in a hybrid application" width="500"></img>
<img src="content/images/guide/upgrade/dom.png" alt="DOM element ownership in a hybrid application" width="500"></img>
</figure>
@ -435,7 +435,7 @@ AngularJS and Angular approaches. Here's what happens:
<figure class='image-display'>
<img src="assets/images/guide/upgrade/change_detection.png" alt="Change detection in a hybrid application" width="600"></img>
<img src="content/images/guide/upgrade/change_detection.png" alt="Change detection in a hybrid application" width="600"></img>
</figure>
@ -473,7 +473,7 @@ that describes Angular assets in metadata. The differences blossom from there.
In a hybrid application we run both versions of Angular at the same time.
That means that we need at least one module each from both AngularJS and Angular.
We will import `UpgradeModule` inside our Angular module, and then use it for
We will import `UpgradeModule` inside our Angular module, and then use it for
bootstrapping our AngularJS module. Let's see how.
@ -542,7 +542,7 @@ Angular from bootstrapping itself in the form of the `ngDoBootstrap` empty class
Now we bootstrap `AppModule` using `platformBrowserDynamic`'s `bootstrapModule` method.
Then we use dependency injection to get a hold of the `UpgradeModule` instance in `AppModule`,
and use it to bootstrap our AngularJS app.
and use it to bootstrap our AngularJS app.
The `upgrade.bootstrap` method takes the exact same arguments as [angular.bootstrap](https://docs.angularjs.org/api/ng/function/angular.bootstrap):
@ -553,7 +553,7 @@ The `upgrade.bootstrap` method takes the exact same arguments as [angular.bootst
We also need to install the `@angular/upgrade` package via `npm install @angular/upgrade --save`
and add a mapping for the `@angular/upgrade/static` package:
and add a mapping for the `@angular/upgrade/static` package:
<code-example path="upgrade-module/src/systemjs.config.1.js" region="upgrade-static-umd" title="systemjs.config.js (map)">
@ -569,7 +569,7 @@ existing AngularJS code works as before _and_ you're ready to run Angular code.
### Using Angular Components from AngularJS Code
<figure>
<img src="assets/images/guide/upgrade/ajs-to-a.png" alt="Using an Angular component from AngularJS code" align="left" style="width:250px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/upgrade/ajs-to-a.png" alt="Using an Angular component from AngularJS code" align="left" style="width:250px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -599,11 +599,11 @@ using the `downgradeComponent()` method. What we get when we do that is an Angul
Because `HeroDetailComponent` is an Angular component, we must also add it to the
Because `HeroDetailComponent` is an Angular component, we must also add it to the
`declarations` in the `AppModule`.
And because this component is being used from the AngularJS module, and is an entry point into
our Angular application, we also need to add it to the `entryComponents` for our
And because this component is being used from the AngularJS module, and is an entry point into
our Angular application, we also need to add it to the `entryComponents` for our
Angular module.
@ -661,7 +661,7 @@ like this:
These inputs and outputs can be supplied from the AngularJS template, and the
`downgradeComponent()` method takes care of bridging them over via the `inputs`
`downgradeComponent()` method takes care of bridging them over via the `inputs`
and `outputs` arrays:
@ -733,7 +733,7 @@ For example, we can easily make multiple copies of the component using `ng-repe
### Using AngularJS Component Directives from Angular Code
<figure>
<img src="assets/images/guide/upgrade/a-to-ajs.png" alt="Using an AngularJS component from Angular code" align="left" style="width:250px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/upgrade/a-to-ajs.png" alt="Using an AngularJS component from Angular code" align="left" style="width:250px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -763,7 +763,7 @@ and a controller:
We can *upgrade* this component to Angular using the `UpgradeComponent` class.
We can *upgrade* this component to Angular using the `UpgradeComponent` class.
By creating a new Angular **directive** that extends `UpgradeComponent` and doing a `super` call
inside it's constructor, we have a fully upgrade AngularJS component to be used inside Angular.
All that is left is to add it to `AppModule`'s `declarations` array.
@ -788,7 +788,7 @@ All that is left is to add it to `AppModule`'s `declarations` array.
Upgraded components are Angular **directives**, instead of **components**, because Angular
is unaware that AngularJS will create elements under it. As far as Angular knows, the upgraded
component is just a directive - a tag - and Angular doesn't have to concern itself with
it's children.
it's children.
</div>
@ -917,7 +917,7 @@ with one input and one output:
We can upgrade this component to Angular, annotate inputs and outputs in the upgrade directive,
We can upgrade this component to Angular, annotate inputs and outputs in the upgrade directive,
and then provide the input and output using Angular template syntax:
@ -936,7 +936,7 @@ and then provide the input and output using Angular template syntax:
### Projecting AngularJS Content into Angular Components
<figure>
<img src="assets/images/guide/upgrade/ajs-to-a-with-projection.png" alt="Projecting AngularJS content into Angular" align="left" style="width:250px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/upgrade/ajs-to-a-with-projection.png" alt="Projecting AngularJS content into Angular" align="left" style="width:250px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -983,7 +983,7 @@ remains in "AngularJS land" and is managed by the AngularJS framework.
### Transcluding Angular Content into AngularJS Component Directives
<figure>
<img src="assets/images/guide/upgrade/a-to-ajs-with-transclusion.png" alt="Projecting Angular content into AngularJS" align="left" style="width:250px; margin-left:-40px;margin-right:10px"></img>
<img src="content/images/guide/upgrade/a-to-ajs-with-transclusion.png" alt="Projecting Angular content into AngularJS" align="left" style="width:250px; margin-left:-40px;margin-right:10px"></img>
</figure>
@ -1045,14 +1045,14 @@ code. For example, we might have a service called `HeroesService` in AngularJS:
We can upgrade the service using a Angular [Factory provider](guide/dependency-injection#factory-providers)
that requests the service from the AngularJS `$injector`.
that requests the service from the AngularJS `$injector`.
We recommend declaring the Factory Provider in a separate `ajs-upgraded-providers.ts` file
so that they are all together, making it easier to reference them, create new ones and
delete them once the upgrade is over.
delete them once the upgrade is over.
It's also recommended to export the `heroesServiceFactory` function so that Ahead-of-Time
compilation can pick it up.
compilation can pick it up.
<code-example path="upgrade-module/src/app/ajs-to-a-providers/ajs-upgraded-providers.ts" title="ajs-upgraded-providers.ts">
@ -1116,8 +1116,8 @@ Again, as with Angular components, register the provider with the `NgModule` by
Now wrap the Angular `Heroes` in an *AngularJS factory function* using `downgradeInjectable()`.
and plug the factory into an AngularJS module.
Now wrap the Angular `Heroes` in an *AngularJS factory function* using `downgradeInjectable()`.
and plug the factory into an AngularJS module.
The name of the AngularJS dependency is up to you:
@ -1140,15 +1140,15 @@ After this, the service is injectable anywhere in our AngularJS code:
We can take advantage of Ahead-of-time (AoT) compilation on hybrid apps just like on any other
Angular application.
The setup for an hybrid app is mostly the same as described in
The setup for an hybrid app is mostly the same as described in
[the Ahead-of-time Compilation chapter](guide/aot-compiler)
save for differences in `index.html` and `main-aot.ts`
Our `index.html` will likely have script tags loading AngularJS files, so the `index.html` we
use for AoT must also load those files.
use for AoT must also load those files.
An easy way to copy them is by adding each to the `copy-dist-files.js` file.
We also need to use `UpgradeModule` to bootstrap a hybrid app after bootstrapping the
We also need to use `UpgradeModule` to bootstrap a hybrid app after bootstrapping the
Module Factory:
@ -1166,8 +1166,8 @@ And that's all we need to get the full benefit of AoT for Angular apps!
The AoT metadata collector will not detect lifecycle hook methods on a parent class' prototype,
so in order for upgraded components to work we needs to implement the lifecycle hooks
on the upgraded component class and forward them to the `UpgradeComponent` parent.
so in order for upgraded components to work we needs to implement the lifecycle hooks
on the upgraded component class and forward them to the `UpgradeComponent` parent.
</div>
@ -1182,9 +1182,9 @@ migrate all the routes in one fell swoop.
But it would be much better to migrate routes one by one as they become upgraded.
The first step to have a dual router setup is to add an Angular root component containing
one outlet for each router.
one outlet for each router.
AngularJS will use `ng-view`, and Angular will use `router-outlet`.
When one is using it's router, the other outlet will be empty.
When one is using it's router, the other outlet will be empty.
<code-example path="upgrade-module/src/app/divide-routes/app.component.ts" title="app.component.ts">
@ -1193,7 +1193,7 @@ When one is using it's router, the other outlet will be empty.
We want to use this component in the body of our `index.html` instead of an AngularJS component:
We want to use this component in the body of our `index.html` instead of an AngularJS component:
<code-example path="upgrade-module/src/index-divide-routes.html" region="body" title="app.component.ts (body)">
@ -1219,9 +1219,9 @@ Next we declare both AngularJS and Angular routes as normal:
In our `app.module.ts` we need to add `AppComponent` to the declarations and boostrap array.
Next we configure the router itself.
Next we configure the router itself.
We want to use [hash navigation](guide/router#-hashlocationstrategy-) in Angular
because that's what we're also using in AngularJS.
because that's what we're also using in AngularJS.
Lastly, and most importantly, we want to use a custom `UrlHandlingStrategy` that will tell
the Angular router which routes it should render - and only those.
@ -1490,7 +1490,7 @@ Let's also add run scripts for the `tsc` TypeScript compiler to `package.json`:
We can now install type definitions for the existing libraries that
we're using but that don't come with prepackaged types: AngularJS and the
we're using but that don't come with prepackaged types: AngularJS and the
Jasmine unit test framework.
@ -1666,7 +1666,7 @@ The project also contains some animations, which we are not yet upgrading in thi
Let's install Angular into the project, along with the SystemJS module loader.
Let's install Angular into the project, along with the SystemJS module loader.
Take a look at the results of the [Setup](guide/setup) instructions
and get the following configurations from there:
@ -1716,14 +1716,14 @@ to load the actual application:
We also need to make a couple of adjustments
to the `systemjs.config.js` file installed during [setup](guide/setup).
We also need to make a couple of adjustments
to the `systemjs.config.js` file installed during [setup](guide/setup).
We want to point the browser to the project root when loading things through SystemJS,
instead of using the `<base>` URL.
We also need to install the `upgrade` package via `npm install @angular/upgrade --save`
and add a mapping for the `@angular/upgrade/static` package.
and add a mapping for the `@angular/upgrade/static` package.
<code-example path="upgrade-phonecat-2-hybrid/systemjs.config.1.js" region="paths" title="systemjs.config.js">
@ -1735,7 +1735,7 @@ and add a mapping for the `@angular/upgrade/static` package.
### Creating the _AppModule_
Now create the root `NgModule` class called `AppModule`.
There is already a file named `app.module.ts` that holds the AngularJS module.
There is already a file named `app.module.ts` that holds the AngularJS module.
Rename it to `app.module.ajs.ts` and update the corresponding script name in the `index.html` as well.
The file contents remain:
@ -1773,10 +1773,10 @@ we first need to import `UpgradeModule` in our `AppModule`, and override it's bo
Our application is currently bootstrapped using the AngularJS `ng-app` directive
attached to the `<html>` element of the host page. This will no longer work with
Angular. We should switch to a JavaScript-driven bootstrap instead.
Angular. We should switch to a JavaScript-driven bootstrap instead.
So, remove the `ng-app` attribute from `index.html`, and instead bootstrap via `src/main.ts`.
This file has been configured as the application entrypoint in `systemjs.config.js`,
This file has been configured as the application entrypoint in `systemjs.config.js`,
so it is already being loaded by the browser.
@ -1802,7 +1802,7 @@ so let's do that next.
#### Why declare _angular_ as _angular.IAngularStatic_?
`@types/angular` is declared as a UMD module, and due to the way
`@types/angular` is declared as a UMD module, and due to the way
<a href="https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#support-for-umd-module-definitions">UMD typings</a>
work, once you have an ES6 `import` statement in a file all UMD typed modules must also be
imported via `import` statements instead of being globally available.
@ -1810,11 +1810,11 @@ imported via `import` statements instead of being globally available.
AngularJS is currently loaded by a script tag in `index.html`, which means that the whole app
has access to it as a global and uses the same instance of the `angular` variable.
If we used `import * as angular from 'angular'` instead we would also need to overhaul how we
load every file in our AngularJS app to use ES6 modules in order to ensure AngularJS was being
load every file in our AngularJS app to use ES6 modules in order to ensure AngularJS was being
loaded correctly.
This is a considerable effort and it often isn't worth it, especially since we are in the
process of moving our our to Angular already.
This is a considerable effort and it often isn't worth it, especially since we are in the
process of moving our our to Angular already.
Instead we declare `angular` as `angular.IAngularStatic` to indicate it is a global variable
and still have full typing support.
@ -1834,7 +1834,7 @@ ngResource and we're using it for two things:
* For loading the details of a single phone into the phone detail component.
We can replace this implementation with an Angular service class, while
keeping our controllers in AngularJS land.
keeping our controllers in AngularJS land.
In the new version, we import the Angular HTTP module and call its `Http` service instead of `ngResource`.
@ -1908,7 +1908,7 @@ Notice that we're importing the `map` operator of the RxJS `Observable` separate
We need to do this for all RxJS operators that we want to use, since Angular
does not load all of them by default.
The new `Phone` service has the same features as the original, `ngResource`-based service.
The new `Phone` service has the same features as the original, `ngResource`-based service.
Because it's an Angular service, we register it with the `NgModule` providers:
@ -1996,7 +1996,7 @@ with Angular's two-way `[(ngModel)]` binding syntax:
Replace the list's `ng-repeat` with an `*ngFor` as
Replace the list's `ng-repeat` with an `*ngFor` as
[described in the Template Syntax page](guide/template-syntax#directives).
Replace the image tag's `ng-src` with a binding to the native `src` property.
@ -2009,10 +2009,10 @@ Replace the image tag's `ng-src` with a binding to the native `src` property.
#### No Angular _filter_ or _orderBy_ filters
The built-in AngularJS `filter` and `orderBy` filters do not exist in Angular,
so we need to do the filtering and sorting ourselves.
so we need to do the filtering and sorting ourselves.
We replaced the `filter` and `orderBy` filters with bindings to the `getPhones()` controller method,
which implements the filtering and ordering logic inside the component itself.
which implements the filtering and ordering logic inside the component itself.
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ts" region="getphones" title="app/phone-list/phone-list.component.ts">
@ -2021,8 +2021,8 @@ which implements the filtering and ordering logic inside the component itself.
Now we need to downgrade our Angular component so we can use it in AngularJS.
Instead of registering a component, we register a `phoneList` *directive*,
Now we need to downgrade our Angular component so we can use it in AngularJS.
Instead of registering a component, we register a `phoneList` *directive*,
a downgraded version of the Angular component.
The `as angular.IDirectiveFactory` cast tells the TypeScript compiler
@ -2035,7 +2035,7 @@ that the return value of the `downgradeComponent` method is a directive factory.
The new `PhoneListComponent` uses the Angular `ngModel` directive, located in the `FormsModule`.
The new `PhoneListComponent` uses the Angular `ngModel` directive, located in the `FormsModule`.
Add the `FormsModule` to `NgModule` imports, declare the new `PhoneListComponent` and
finally add it to `entryComponents` since we downgraded it:
@ -2057,8 +2057,8 @@ Now set the remaining `phone-detail.component.ts` as follows:
This is similar to the phone list component.
The new wrinkle is the `RouteParams` type annotation that identifies the `routeParams` dependency.
This is similar to the phone list component.
The new wrinkle is the `RouteParams` type annotation that identifies the `routeParams` dependency.
The AngularJS injector has an AngularJS router dependency called `$routeParams`,
which was injected into `PhoneDetails` when it was still an AngularJS controller.
@ -2128,7 +2128,7 @@ Let's turn that into an Angular **pipe**.
There is no upgrade method to convert filters into pipes.
You won't miss it.
It's easy to turn the filter function into an equivalent Pipe class.
It's easy to turn the filter function into an equivalent Pipe class.
The implementation is the same as before, repackaged in the `transform` method.
Rename the file to `checkmark.pipe.ts` to conform with Angular conventions:
@ -2154,7 +2154,7 @@ remove the filter &lt;script&gt; tag from `index.html`:
To use AoT with our hybrid app we have to first set it up like any other Angular application,
as shown in [the Ahead-of-time Compilation chapter](guide/aot-compiler).
Then we have to change `main-aot.ts` bootstrap also bootstrap the AngularJS app
Then we have to change `main-aot.ts` bootstrap also bootstrap the AngularJS app
via `UpgradeModule`:
@ -2198,7 +2198,7 @@ their Angular counterparts, even though we're still serving them from the Angula
Most AngularJS apps have more than a couple of routes though, and it's very helpful to migrate
one route at a time.
Let's start by migrating the initial `/` and `/phones` routes to Angular,
Let's start by migrating the initial `/` and `/phones` routes to Angular,
while keeping `/phones/:phoneId` in the AngularJS router.
#### Add the Angular router
@ -2207,7 +2207,7 @@ Angular has an [all-new router](guide/router).
Like all routers, it needs a place in the UI to display routed views.
For Angular that's the `<router-outlet>` and it belongs in a *root component*
at the top of the applications component tree.
at the top of the applications component tree.
We don't yet have such a root component, because the app is still managed as an AngularJS app.
Create a new `app.component.ts` file with the following `AppComponent` class:
@ -2223,7 +2223,7 @@ It has a simple template that only includes the `<router-outlet>` for Angular ro
and `ng-view` for AngularJS routes.
This component just renders the contents of the active route and nothing else.
The selector tells Angular to plug this root component into the `<phonecat-app>`
The selector tells Angular to plug this root component into the `<phonecat-app>`
element on the host web page when the application launches.
Add this `<phonecat-app>` element to the `index.html`.
@ -2239,7 +2239,7 @@ It replaces the old AngularJS `ng-view` directive:
#### Create the _Routing Module_
A router needs configuration whether it's the AngularJS or Angular or any other router.
The details of Angular router configuration are best left to the [Routing documentation](guide/router)
The details of Angular router configuration are best left to the [Routing documentation](guide/router)
which recommends that you create a `NgModule` dedicated to router configuration
(called a _Routing Module_).
@ -2251,10 +2251,10 @@ which recommends that you create a `NgModule` dedicated to router configuration
This module defines a `routes` object with one route to the phone list component
and a default route for the empty path.
and a default route for the empty path.
It passes the `routes` to the `RouterModule.forRoot` method which does the rest.
A couple of extra providers enable routing with "hash" URLs such as `#!/phones`
A couple of extra providers enable routing with "hash" URLs such as `#!/phones`
instead of the default "push state" strategy.
There's a twist to our Routing Module though: we're also adding a custom `UrlHandlingStrategy`
@ -2262,7 +2262,7 @@ that tells the Angular router to only process the `/` and `/phones` routes.
Now update the `AppModule` to import this `AppRoutingModule` and also the
declare the root `AppComponent` as the bootstrap component.
That tells Angular that it should bootstrap the app with the _root_ `AppComponent` and
That tells Angular that it should bootstrap the app with the _root_ `AppComponent` and
insert it's view into the host web page.
We can also remove the `ngDoBootstrap()` override from `app.module.ts` since we are now
@ -2289,7 +2289,7 @@ Now we need to tell the AngularJS router to only process the `/phones/:phoneId`
#### Generate links for each phone
We no longer have to hardcode the links to phone details in the phone list.
We no longer have to hardcode the links to phone details in the phone list.
We can generate data bindings for each phone's `id` to the `routerLink` directive
and let that directive construct the appropriate URL to the `PhoneDetailComponent`:
@ -2332,11 +2332,11 @@ Extract the `phoneId` from the `ActivatedRoute.snapshot.params` and fetch the ph
Since this was the last route we want to migrate over, we can also now delete the last
Since this was the last route we want to migrate over, we can also now delete the last
route config from `app/app.config.ts`, and add it to the Angular router configuration.
We don't need our `UrlHandlingStrategy` anymore either, since now Angular is processing all
routes.
routes.
<code-example path="upgrade-phonecat-4-final/app/app-routing.module.ts" title="app/app-routing.module.ts">
@ -2356,8 +2356,8 @@ do with removing code - which of course is every programmer's favorite task!
The application is still bootstrapped as a hybrid app.
There's no need for that anymore.
Switch the bootstrap method of the application from the `UpgradeAdapter`
to the Angular way.
Switch the bootstrap method of the application from the `UpgradeAdapter`
to the Angular way.
<code-example path="upgrade-phonecat-4-final/app/main.ts" title="main.ts">
@ -2366,11 +2366,11 @@ to the Angular way.
If you haven't already, remove all references to the `UpgradeModule` from `app.module.ts`,
as well as any [Factory provider](guide/upgrade#making-angularjs-dependencies-injectable-to-angular)
If you haven't already, remove all references to the `UpgradeModule` from `app.module.ts`,
as well as any [Factory provider](guide/upgrade#making-angularjs-dependencies-injectable-to-angular)
for AngularJS services, and the `app/ajs-upgraded-providers.ts` file.
Also remove any `downgradeInjectable()` or `downgradeComponent()` you find,
Also remove any `downgradeInjectable()` or `downgradeComponent()` you find,
together with the associated AngularJS factory or directive declarations.
Since we have no downgraded components anymore, we also don't need to have them listed
in `entryComponents` either.
@ -2453,8 +2453,8 @@ The following change is needed in `protractor-conf.js` to sync with hybrid apps:
The next set of changes is when we start to upgrade components and their template to Angular.
This is because the E2E tests have matchers that are specific to AngularJS.
The next set of changes is when we start to upgrade components and their template to Angular.
This is because the E2E tests have matchers that are specific to AngularJS.
For PhoneCat we need to make the following changes in order to make things work with Angular:
@ -2596,7 +2596,7 @@ When the bootstrap method is switched from that of `UpgradeModule` to
pure Angular, AngularJS ceases to exist on the page completely.
At this point we need to tell Protractor that it should not be looking for
an AngularJS app anymore, but instead it should find *Angular apps* from
the page.
the page.
Replace the `ng12Hybrid` previously added with the following in `protractor-conf.js`:

View File

@ -86,7 +86,7 @@ In this case, `target` refers to the [`<input>` element](https://developer.mozil
After each call, the `onKey()` method appends the contents of the input box value to the list
in the component's `values` property, followed by a separator character (|).
The [interpolation](guide/template-syntax#interpolation)
displays the accumulating input box changes from the `values` property.
displays the accumulating input box changes from the `values` property.
Suppose the user enters the letters "abc", and then backspaces to remove them one by one.
Here's what the UI displays:
@ -98,7 +98,7 @@ Here's what the UI displays:
<figure class='image-display'>
<img src='assets/images/guide/user-input/keyup1-anim.gif' alt="key up 1"></img>
<img src='content/images/guide/user-input/keyup1-anim.gif' alt="key up 1"></img>
</figure>
@ -127,7 +127,7 @@ for `event.target.value` in which case the same user input would produce:
### Type the _$event_
The example above casts the `$event` as an `any` type.
That simplifies the code at a cost.
That simplifies the code at a cost.
There is no type information
that could reveal properties of the event object and prevent silly mistakes.
@ -139,7 +139,7 @@ The following example rewrites the method with types:
The `$event` is now a specific `KeyboardEvent`.
The `$event` is now a specific `KeyboardEvent`.
Not all elements have a `value` property so it casts `target` to an input element.
The `OnKey` method more clearly expresses what it expects from the template and how it interprets the event.
@ -147,7 +147,7 @@ The `OnKey` method more clearly expresses what it expects from the template and
Typing the event object reveals a significant objection to passing the entire DOM event into the method:
the component has too much awareness of the template details.
It can't extract information without knowing more than it should about the HTML implementation.
That breaks the separation of concerns between the template (_what the user sees_)
That breaks the separation of concerns between the template (_what the user sees_)
and the component (_how the application processes user data_).
The next section shows how to use template reference variables to address this problem.
@ -181,7 +181,7 @@ Type something in the input box, and watch the display update with each keystrok
<figure class='image-display'>
<img src='assets/images/guide/user-input/keyup-loop-back-anim.gif' alt="loop back"></img>
<img src='content/images/guide/user-input/keyup-loop-back-anim.gif' alt="loop back"></img>
</figure>
@ -195,8 +195,8 @@ Type something in the input box, and watch the display update with each keystrok
Angular updates the bindings (and therefore the screen)
only if the app does something in response to asynchronous events, such as keystrokes.
This example code binds the `keyup` event
to the number 0, the shortest template statement possible.
While the statement does nothing useful,
to the number 0, the shortest template statement possible.
While the statement does nothing useful,
it satisfies Angular's requirement so that Angular will update the screen.
</div>
@ -223,7 +223,7 @@ The `(keyup)` event handler hears *every keystroke*.
Sometimes only the _Enter_ key matters, because it signals that the user has finished typing.
One way to reduce the noise would be to examine every `$event.keyCode` and take action only when the key is _Enter_.
There's an easier way: bind to Angular's `keyup.enter` pseudo-event.
There's an easier way: bind to Angular's `keyup.enter` pseudo-event.
Then Angular calls the event handler only when the user presses _Enter_.
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-3" title="src/app/keyup.components.ts (v3)" linenums="false">
@ -235,7 +235,7 @@ Then Angular calls the event handler only when the user presses _Enter_.
Here's how it works.
<figure class='image-display'>
<img src='assets/images/guide/user-input/keyup3-anim.gif' alt="key up 3"></img>
<img src='content/images/guide/user-input/keyup3-anim.gif' alt="key up 3"></img>
</figure>
@ -269,7 +269,7 @@ clicking **Add**.
<figure class='image-display'>
<img src='assets/images/guide/user-input/little-tour-anim.gif' alt="Little Tour of Heroes"></img>
<img src='content/images/guide/user-input/little-tour-anim.gif' alt="Little Tour of Heroes"></img>
</figure>
@ -336,4 +336,4 @@ quickly become verbose and clumsy when handling large amounts of user input.
Two-way data binding is a more elegant and compact way to move
values between data entry fields and model properties.
The next page, `Forms`, explains how to write
two-way bindings with `NgModel`.
two-way bindings with `NgModel`.

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

Before

Width:  |  Height:  |  Size: 320 KiB

After

Width:  |  Height:  |  Size: 320 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 220 KiB

After

Width:  |  Height:  |  Size: 220 KiB

View File

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 127 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 851 KiB

After

Width:  |  Height:  |  Size: 851 KiB

View File

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 221 KiB

After

Width:  |  Height:  |  Size: 221 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Some files were not shown because too many files have changed in this diff Show More