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 ## Quickstart example: Transitioning between two states
<figure> <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> </figure>
@ -172,7 +172,7 @@ controls the timing of switching between one set of styles and the next:
<figure class='image-display'> <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> </figure>
@ -220,7 +220,7 @@ transitions that apply regardless of which state the animation is in. For exampl
<figure class='image-display'> <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> </figure>
@ -237,7 +237,7 @@ regardless of what state it was in before it left.
<figure class='image-display'> <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> </figure>
@ -247,7 +247,7 @@ The wildcard state `*` also matches `void`.
## Example: Entering and leaving ## Example: Entering and leaving
<figure> <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> </figure>
@ -258,7 +258,7 @@ entering and leaving of elements:
* Enter: `void => *` * Enter: `void => *`
* Leave: `* => 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. 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"> <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 ## Example: Entering and leaving from different states
<figure> <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> </figure>
@ -313,7 +313,7 @@ This gives you fine-grained control over each transition:
<figure class='image-display'> <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> </figure>
@ -346,7 +346,7 @@ If you don't provide a unit when specifying dimension, Angular assumes the defau
## Automatic property calculation ## Automatic property calculation
<figure> <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> </figure>
@ -405,7 +405,7 @@ and the delay (or as the *second* value when there is no delay):
<figure> <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> </figure>
@ -427,7 +427,7 @@ slight delay of 10 milliseconds as specified in `'0.2s 10 ease-out'`:
## Multi-step animations with keyframes ## Multi-step animations with keyframes
<figure> <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> </figure>
@ -461,7 +461,7 @@ offsets receive offsets `0`, `0.5`, and `1`.
## Parallel animation groups ## Parallel animation groups
<figure> <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> </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`. `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_ Luckily, there is a Rollup plugin that modifies _RxJs_
to use the ES `import` and `export` statements that Rollup requires. to use the ES `import` and `export` statements that Rollup requires.
Rollup then preserves the parts of `RxJS` referenced by the application Rollup then preserves the parts of `RxJS` referenced by the application
in the final bundle. Using it is straigthforward. Add the following to in the final bundle. Using it is straigthforward. Add the following to
the `plugins` array in `rollup-config.js`: 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"> <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* *Minification*
Rollup tree shaking reduces code size considerably. Minification makes it smaller still. 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: 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"> <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 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. the code into an even smaller package going over the wire.
</div> </div>
{@a run-rollup} {@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_. 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'> <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> </figure>
</a> </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> <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> </figure>
@ -64,23 +64,23 @@ Learn these building blocks, and you're on your way.
## Modules ## Modules
<figure> <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> </figure>
Angular apps are modular and Angular has its own modularity system called _Angular modules_ or _NgModules_. 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. This page introduces modules; the [Angular modules](guide/ngmodule) page covers them in depth.
<br class="l-clear-both"><br> <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`. 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, _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. 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: The most important properties are:
* `declarations` - the _view classes_ that belong to this module. * `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). 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 * `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. 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. that hosts all other app views. Only the _root module_ should set this `bootstrap` property.
Here's a simple root module: 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> </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. 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"> <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. 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. 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. 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> <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> </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. Each Angular library name begins with the `@angular` prefix.
@ -244,7 +244,7 @@ Learn more from the [Angular modules](guide/ngmodule) page.
<figure> <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> </figure>
@ -284,7 +284,7 @@ Your app can take action at each moment in this lifecycle through optional [life
## Templates ## Templates
<figure> <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> </figure>
@ -314,7 +314,7 @@ The `HeroDetailComponent` is a **child** of the `HeroListComponent`.
<figure> <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> </figure>
@ -330,7 +330,7 @@ Notice how `<hero-detail>` rests comfortably among native HTML elements. Custom
## Metadata ## Metadata
<figure> <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> </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. * `providers`: array of **dependency injection providers** for services that the component requires.
This is one way to tell Angular that the component's constructor requires a `HeroService` This is one way to tell Angular that the component's constructor requires a `HeroService`
so it can get the list of heroes to display. so it can get the list of heroes to display.
<figure> <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> </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. read as any experienced jQuery programmer can attest.
<figure> <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> </figure>
@ -454,7 +454,7 @@ from the root of the application component tree through all child components.
<figure> <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> </figure>
@ -463,7 +463,7 @@ Data binding plays an important role in communication
between a template and its component.<br class="l-clear-both"> between a template and its component.<br class="l-clear-both">
<figure> <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> </figure>
@ -478,7 +478,7 @@ Data binding is also important for communication between parent and child compon
## Directives ## Directives
<figure> <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> </figure>
@ -556,7 +556,7 @@ Of course, you can also write your own directives. Components such as
## Services ## Services
<figure> <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> </figure>
@ -624,7 +624,7 @@ application logic into services and make those services available to components
## Dependency injection ## Dependency injection
<figure> <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> </figure>
@ -656,7 +656,7 @@ This is *dependency injection*.
The process of `HeroService` injection looks a bit like this: The process of `HeroService` injection looks a bit like this:
<figure> <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> </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. Learn about them in the [Structural Directives](guide/structural-directives) guide.
*Attribute directives* are used as attributes of elements. *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, [Template Syntax](guide/template-syntax) guide, for example,
can change several element styles at the same time. 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. This also reduces the risk of colliding with third-party directive names.
Make sure you do **not** prefix the `highlight` directive name with **`ng`** because Make sure you do **not** prefix the `highlight` directive name with **`ng`** because
that prefix is reserved for Angular and using it could cause bugs that are difficult to diagnose. 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. 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. called `HighlightDirective`, which contains the logic for the directive.
Exporting `HighlightDirective` makes it accessible to other components. 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'> <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> </figure>
@ -179,7 +179,7 @@ Now when the app runs, the `myHighlight` directive highlights the paragraph text
### Your directive isn't working? ### Your directive isn't working?
Did you remember to add the directive to the `declarations` attribute of `@NgModule`? Did you remember to add the directive to the `declarations` attribute of `@NgModule`?
It is easy to forget! It is easy to forget!
Open the console in the browser tools and look for an error like this: Open the console in the browser tools and look for an error like this:
@ -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. 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'> <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> </figure>
@ -438,7 +438,7 @@ Here are the harness and directive in action.
<figure class='image-display'> <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> </figure>
@ -491,7 +491,7 @@ Here's how the harness should work when you're done coding.
<figure class='image-display'> <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> </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`, * The `myHighlight` property on the left refers to an _aliased_ property of the `HighlightDirective`,
not a property of the template's component. There are trust issues. not a property of the template's component. There are trust issues.
Therefore, the directive property must carry the `@Input` decorator. Therefore, the directive property must carry the `@Input` decorator.

View File

@ -123,7 +123,7 @@ Your app greets you with a message:
<figure class='image-display'> <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> </figure>
@ -161,7 +161,7 @@ Open `src/app/app.component.css` and give the component some style.
<figure class='image-display'> <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> </figure>

View File

@ -54,7 +54,7 @@ The running application displays three heroes:
<figure class='image-display'> <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> </figure>
@ -98,7 +98,7 @@ Here's the `NameParentComponent` demonstrating name variations including a name
<figure class='image-display'> <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> </figure>
@ -156,7 +156,7 @@ Here's the output of a button-pushing sequence:
<figure class='image-display'> <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> </figure>
@ -210,7 +210,7 @@ and the method processes it:
<figure class='image-display'> <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> </figure>
@ -272,7 +272,7 @@ Here we see the parent and child working together.
<figure class='image-display'> <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> </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, When the parent component *class* requires that kind of access,
***inject*** the child component into the parent as a *ViewChild*. ***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. [Countdown Timer](guide/component-communication#countdown-timer-example) example.
Neither its appearance nor its behavior will change. Neither its appearance nor its behavior will change.
The child [CountdownTimerComponent](guide/component-communication#countdown-timer-example) is the same as well. 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'> <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> </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'> <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> </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. and confirm that the three `HeroBioComponent` instances have their own cached hero data.
<figure class='image-display'> <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> </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: It looks like this, with the hero's telephone number from `HeroContactComponent` projected above the hero description:
<figure class='image-display'> <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> </figure>
@ -440,7 +440,7 @@ Thanks to `@Optional()`, Angular sets the `loggerService` to null and the rest o
Here's the `HeroBiosAndContactsComponent` in action. Here's the `HeroBiosAndContactsComponent` in action.
<figure class='image-display'> <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> </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. with the gratuitous "!!!", indicating that the logger was found.
<figure class='image-display'> <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> </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. The following image shows the effect of mousing over the `<hero-bios-and-contacts>` tag.
<figure class='image-display'> <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> </figure>
{@a providers} {@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. 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. 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'> <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> </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 `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 *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: 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'> <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> </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: The following image, which displays the logging date, confirms the point:
<figure class='image-display'> <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> </figure>
@ -849,7 +849,7 @@ But *no class* in this application inherits from `MinimalLogger`.
The `LoggerService` and the `DateLoggerService` _could_ have inherited from `MinimalLogger`. The `LoggerService` and the `DateLoggerService` _could_ have inherited from `MinimalLogger`.
They could have _implemented_ it instead in the manner of an interface. 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. The `MinimalLogger` is used exclusively as a dependency injection token.
When you use a class this way, it's called a ***class-interface***. 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'> <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> </figure>
@ -1003,8 +1003,8 @@ These complications argue for *avoiding component inheritance*.
## Find a parent component by injection ## Find a parent component by injection
Application components often need to share information. Application components often need to share information.
More loosely coupled techniques such as data binding and service sharing More loosely coupled techniques such as data binding and service sharing
are preferable. But sometimes it makes sense for one component are preferable. But sometimes it makes sense for one component
to have a direct reference to another component to have a direct reference to another component
perhaps to access values or call methods on that 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 no public API for inspecting and traversing that tree.
There is an API for acquiring a child reference. 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/). in the [API Reference](api/).
There is no public API for acquiring a parent reference. 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, is there for safety,
the <live-example name="dependency-injection-in-action"></live-example> the <live-example name="dependency-injection-in-action"></live-example>
confirms that the `alex` parameter is set. 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. Looking for components that implement an interface would be better.
That's not possible because TypeScript interfaces disappear That's not possible because TypeScript interfaces disappear
from the transpiled JavaScript, which doesn't support interfaces. from the transpiled JavaScript, which doesn't support interfaces.
There's no artifact to look for. There's no artifact to look for.
</div> </div>
@ -1087,7 +1087,7 @@ There's no artifact to look for.
This isn't necessarily good design. 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*. inject its parent via the parent's base class*.
The sample's `CraigComponent` explores this question. [Looking back](guide/dependency-injection-in-action#alex), 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; 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). 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 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`: 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. [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. 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: 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"> <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: Here's *Alex* and family in action:
<figure class='image-display'> <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> </figure>
@ -1215,7 +1215,7 @@ Here's *Alice*, *Barry* and family in action:
<figure class='image-display'> <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> </figure>

View File

@ -18,7 +18,7 @@ The final UI looks like this:
<figure class='image-display'> <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> </figure>
@ -126,7 +126,7 @@ inside the `<my-app>` tag.
Now run the app. It should display the title and hero name: Now run the app. It should display the title and hero name:
<figure class='image-display'> <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> </figure>
@ -233,7 +233,7 @@ Now the heroes appear in an unordered list.
<figure class='image-display'> <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> </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`. Take a closer look at the methods in `ad-banner.component.ts`.
`AdBannerComponent` takes an array of `AdItem` objects as input, `AdBannerComponent` takes an array of `AdItem` objects as input,
which ultimately comes from `AdService`. `AdItem` objects specify which ultimately comes from `AdService`. `AdItem` objects specify
the type of component to load and any data to bind to the the type of component to load and any data to bind to the
component.`AdService` returns the actual ads making up the ad campaign. component.`AdService` returns the actual ads making up the ad campaign.
Passing an array of components to `AdBannerComponent` allows for a 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` After `loadComponent()` selects an ad, it uses `ComponentFactoryResolver`
to resolve a `ComponentFactory` for each specific component. to resolve a `ComponentFactory` for each specific component.
The `ComponentFactory` then creates an instance of each component. The `ComponentFactory` then creates an instance of each component.
Next, you're targeting the `viewContainerRef` that Next, you're targeting the `viewContainerRef` that
exists on this specific instance of the component. How do you know it's 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 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. directive you set up earlier to tell Angular where to insert dynamic components.
As you may recall, `AdDirective` injects `ViewContainerRef` into its constructor. 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. 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`. 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: The final ad banner looks like this:
<figure class='image-display'> <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> </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 @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 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. 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. 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. render a simple form with different control types and validation.
It's a primitive start. It's a primitive start.
It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience. It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience.
All such greatness has humble beginnings. 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. online application experience for heroes seeking employment.
The agency is constantly tinkering with the application process. The agency is constantly tinkering with the application process.
You can create the forms on the fly *without changing the application code*. 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). This cookbook uses [reactive forms](guide/reactive-forms).
Reactive forms belongs to a different `NgModule` called `ReactiveFormsModule`, Reactive forms belongs to a different `NgModule` called `ReactiveFormsModule`,
so in order to access any reactive forms directives, you have to import so in order to access any reactive forms directives, you have to import
`ReactiveFormsModule` from the `@angular/forms` library. `ReactiveFormsModule` from the `@angular/forms` library.
Bootstrap the `AppModule` in `main.ts`. 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. 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. 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. 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`. 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. 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} {@a form-component}
## Question form components ## 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. 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. It presents a list of questions, each bound to a `<df-question>` component element.
The `<df-question>` tag matches the `DynamicFormQuestionComponent`, 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. 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 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. underlying control objects, populated from the question model with display and validation rules.
`formControlName` and `formGroup` are directives defined in `formControlName` and `formGroup` are directives defined in
`ReactiveFormsModule`. The templates can access these directives `ReactiveFormsModule`. The templates can access these directives
directly since you imported `ReactiveFormsModule` from `AppModule`. directly since you imported `ReactiveFormsModule` from `AppModule`.
{@a questionnaire-data} {@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`. 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. 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`. 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. 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} {@a dynamic-template}
## 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 no references to any specific hero question
outside the objects returned by `QuestionService`. 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: The final form looks like this:
<figure class='image-display'> <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> </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. 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'> <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> </figure>
@ -74,7 +74,7 @@ If you delete the hero name, the form displays a validation error in an attentio
<figure class='image-display'> <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> </figure>
@ -148,7 +148,7 @@ You can create a new hero like this:
## Create a form component ## 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. to handle data and user interactions programmatically.
Begin with the class because it states, in brief, what the hero editor can do. Begin with the class because it states, in brief, what the hero editor can do.
@ -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. 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'> <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> </figure>
@ -413,8 +413,8 @@ You left yourself a note to throw it away when you're done.
Focus on the binding syntax: `[(ngModel)]="..."`. Focus on the binding syntax: `[(ngModel)]="..."`.
You need one more addition to display the data. Declare You need one more addition to display the data. Declare
a template variable for the form. Update the `<form>` tag with a template variable for the form. Update the `<form>` tag with
`#heroForm="ngForm"` as follows: `#heroForm="ngForm"` as follows:
@ -456,7 +456,7 @@ At some point it might look like this:
<figure class='image-display'> <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> </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'> <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> </figure>
@ -642,7 +642,7 @@ The actions and effects are as follows:
<figure class='image-display'> <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> </figure>
@ -651,7 +651,7 @@ You should see the following transitions and class names:
<figure class='image-display'> <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> </figure>
@ -671,7 +671,7 @@ on the left of the input box:
<figure class='image-display'> <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> </figure>
@ -705,7 +705,7 @@ When the user deletes the name, the form should look like this:
<figure class='image-display'> <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> </figure>
@ -833,8 +833,8 @@ to the hero form component's `onSubmit()` method:
You'd already defined a template reference variable, You'd already defined a template reference variable,
`#heroForm`, and initialized it with the value "ngForm". `#heroForm`, and initialized it with the value "ngForm".
Now, use that variable to access the form with the Submit button. 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. it doesn't do anything useful yet.
Now if you delete the Name, you violate the "required" rule, which Now if you delete the Name, you violate the "required" rule, which

View File

@ -55,7 +55,7 @@ open simultaneously.
<figure class='image-display'> <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> </figure>
@ -149,7 +149,7 @@ Each tax return component has the following characteristics:
<figure class='image-display'> <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> </figure>
@ -234,7 +234,7 @@ Component (B) is the parent of another component (C) that defines its own, even
<figure class='image-display'> <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> </figure>
@ -247,7 +247,7 @@ its injector produces an instance of `Car` resolved by injector (C) with an `Eng
<figure class='image-display'> <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> </figure>

View File

@ -178,7 +178,7 @@ The app uses the Angular <code>Http</code> client to communicate via **XMLHttpRe
It works like this: It works like this:
<figure class='image-display'> <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> </figure>
@ -333,13 +333,13 @@ and `map()` is one of the RxJS *operators*.
## RxJS library ## RxJS library
<a href="http://reactivex.io/rxjs" title="RxJS Reactive Extensions">RxJS</a> <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. <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 All of the Developer Guide samples have installed the RxJS npm package
because Observables are used widely in Angular applications. because Observables are used widely in Angular applications.
_This_ app needs it when working with the HTTP client. _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_. _you must import the RxJS operators individually_.
### Enable RxJS operators ### 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 You can follow the Promise `then(this.extractData).catch(this.handleError)` pattern as in
this example. this example.
Alternatively, you can call `toPromise(success, fail)`. The Observable's `map` callback moves to the 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 first *success* parameter and its `catch` callback to the second *fail* parameter
in this pattern: `.toPromise(this.extractData, this.handleError)`. in this pattern: `.toPromise(this.extractData, this.handleError)`.
The `errorHandler` forwards an error message as a failed `Promise` instead of a failed `Observable`. 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 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. more `then()` and `catch()` calls, getting a new promise each time.
The `subscribe()` method returns a `Subscription`. A `Subscription` is not another `Observable`. 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. 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`. The `Subscription` object has a different purpose, signified by its primary method, `unsubscribe`.
To understand the implications and consequences of subscriptions, To understand the implications and consequences of subscriptions,
watch [Ben Lesh's talk on Observables](https://www.youtube.com/watch?v=3LKMwkuK0ZE) 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). 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'> <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> </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, 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. 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[]>`). Observable array of string results (`Observable<string[]>`).
Instead of subscribing to the Observable inside the component, as in the `HeroListComponent`, 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 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: Here's how it will work after refactoring:
<figure class='image-display'> <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> </figure>

View File

@ -9,7 +9,7 @@ Angular calls lifecycle hook methods on directives and components as it creates,
<figure> <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> </figure>
@ -262,7 +262,7 @@ calls the lifecycle hook methods in the following sequence at specific moments:
{@a interface-optional} {@a interface-optional}
## Interfaces are optional (technically) ## 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. This snapshot reflects the state of the log after the user clicked the *Create...* button and then the *Destroy...* button.
<figure class='image-display'> <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> </figure>
@ -549,7 +549,7 @@ with an entry in the *Hook Log* as seen here:
<figure class='image-display'> <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> </figure>
@ -672,7 +672,7 @@ Here's the sample in action as the user makes changes.
<figure class='image-display'> <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> </figure>
@ -718,7 +718,7 @@ so you can see how often `DoCheck` is called. The results are illuminating:
<figure class='image-display'> <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> </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. 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!). 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. for one turn of the browser's JavaScript cycle and that's just long enough.
Here's *AfterView* in action: Here's *AfterView* in action:
<figure class='image-display'> <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> </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. In this case, the projected content is the `<my-child>` from the parent.
<figure class='image-display'> <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> </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. 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. 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'> <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> </figure>
@ -237,7 +237,7 @@ Now you need a component to demonstrate the pipe.
<figure class='image-display'> <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> </figure>
@ -285,7 +285,7 @@ your pipe and two-way data binding with `ngModel`.
<figure class='image-display'> <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> </figure>
@ -372,7 +372,7 @@ code with checkbox switches and additional displays to help you experience these
<figure class='image-display'> <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> </figure>
@ -559,7 +559,7 @@ The component renders as the following:
<figure class='image-display'> <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> </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. 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 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`. They even have their own modules: the `ReactiveFormsModule` and the `FormsModule`.
### _Reactive_ forms ### _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 that favors explicit management of the data flowing between
a non-UI _data model_ (typically retrieved from a server) and a a non-UI _data model_ (typically retrieved from a server) and a
UI-oriented _form model_ that retains the states UI-oriented _form model_ that retains the states
and values of the HTML controls on screen. Reactive forms offer the ease and values of the HTML controls on screen. Reactive forms offer the ease
of using reactive patterns, testing, and validation. of using reactive patterns, testing, and validation.
With _reactive_ forms, you create a tree of Angular form control objects 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 in the component class and bind them to native form control elements in the
component template, using techniques described in this guide. component template, using techniques described in this guide.
You create and manipulate form control objects directly in the You create and manipulate form control objects directly in the
component class. As the component class has immediate access to both the data 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 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 the form controls and pull user-changed values back out. The component can
observe changes in form control state and react to those changes. 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 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"). 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 You won't encounter the timing issues that sometimes plague a template-driven form
and reactive forms can be easier to unit test. 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_, preserves the immutability of the _data model_,
treating it as a pure source of original values. treating it as a pure source of original values.
Rather than update the data model directly, Rather than update the data model directly,
the component extracts user changes and forwards them to an external component or service, the component extracts user changes and forwards them to an external component or service,
which does something with them (such as saving them) which does something with them (such as saving them)
and returns a new _data model_ to the component that reflects the updated model state. 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, 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. but it does facilitate the reactive programming approach should you choose to use it.
### _Template-driven_ forms ### _Template-driven_ forms
_Template-driven_ forms, introduced in the [Template guide](guide/forms), take a completely different approach. _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 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 bind them to _data model_ properties in the component, using directives
like `ngModel`. like `ngModel`.
You don't create Angular form control objects. Angular directives You don't create Angular form control objects. Angular directives
create them for you, using the information in your data bindings. 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`. 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. Angular updates the mutable _data model_ with user changes as they happen.
For this reason, the `ngModel` directive is not part of the ReactiveFormsModule. 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") [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} {@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. 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. 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 You can immediately update a value or drill down through the descendents of the parent form
because all controls are always available. because all controls are always available.
Template-driven forms delegate creation of their form controls to directives. 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. 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 That means you must wait a tick before manipulating any of the controls
from within the component class. 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"), [`ngAfterViewInit` lifecycle hook](guide/lifecycle-hooks#afterview "Lifecycle hooks guide: AfterView"),
you'll discover that it has no children. you'll discover that it has no children.
You must wait a tick, using `setTimeout`, before you can 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. 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. The asynchrony of template-driven forms also complicates unit testing.
You must wrap your test block in `async()` or `fakeAsync()` to You must wrap your test block in `async()` or `fakeAsync()` to
avoid looking for values in the form that aren't there yet. avoid looking for values in the form that aren't there yet.
With reactive forms, everything is available when you expect it to be. 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". Neither is "better".
They're two different architectural paradigms, They're two different architectural paradigms,
with their own strengths and weaknesses. with their own strengths and weaknesses.
Choose the approach that works best for you. Choose the approach that works best for you.
You may decide to use both in the same application. You may decide to use both in the same application.
The balance of this _reactive forms_ guide explores the _reactive_ paradigm and The balance of this _reactive forms_ guide explores the _reactive_ paradigm and
concentrates exclusively on reactive forms techniques. concentrates exclusively on reactive forms techniques.
For information on _template-driven forms_, see the [_Forms_](guide/forms) guide. 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. 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 ## 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`) for creating a new project folder (perhaps called `reactive-forms`)
based on the _QuickStart seed_. 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` The file exports two classes and two constants. The `Address`
and `Hero` classes define the application _data model_. and `Hero` classes define the application _data model_.
The `heroes` and `states` constants supply the test data. 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 ## 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: `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`. Next, create an exported `HeroDetailComponent` class with a `FormControl`.
`FormControl` is a directive that allows you to create and manage `FormControl` is a directive that allows you to create and manage
a `FormControl` instance directly. a `FormControl` instance directly.
@ -218,14 +218,14 @@ a `FormControl` instance directly.
Here you are creating a `FormControl` called `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. 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. the initial data value, an array of validators, and an array of async validators.
This simple control doesn't have data or 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"> <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 To let Angular know that this is the input that you want to
associate to the `name` `FormControl` in the class, associate to the `name` `FormControl` in the class,
you need `[formControl]="name"` in the template on the `<input>`. 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>, <a href="http://getbootstrap.com/" title="Bootstrap CSS">Bootstrap CSS library</a>,
not Angular. not Angular.
It _styles_ the form but in no way impacts the logic of the form. 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_ ## Import the _ReactiveFormsModule_
The HeroDetailComponent template uses `formControlName` The HeroDetailComponent template uses `formControlName`
directive from the `ReactiveFormsModule`. directive from the `ReactiveFormsModule`.
In this sample, you declare the `HeroDetailComponent` in the `AppModule`. In this sample, you declare the `HeroDetailComponent` in the `AppModule`.
Therefore, do the following three things in `app.module.ts`: Therefore, do the following three things in `app.module.ts`:
1. Use a JavaScript `import` statement to access 1. Use a JavaScript `import` statement to access
the `ReactiveFormsModule` and the `HeroDetailComponent`. the `ReactiveFormsModule` and the `HeroDetailComponent`.
1. Add `ReactiveFormsModule` to the `AppModule`'s `imports` list. 1. Add `ReactiveFormsModule` to the `AppModule`'s `imports` list.
1. Add `HeroDetailComponent` to the declarations array. 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. It may be helpful to read a brief description of the core form classes.
* [_AbstractControl_](api/forms/index/AbstractControl-class "API Reference: AbstractControl") * [_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`. `FormControl`, `FormGroup`, and `FormArray`.
It provides their common behaviors and properties, some of which are _observable_. 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. 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. 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'> <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> </figure>
@ -362,9 +362,9 @@ Now that everything is wired up, the browser should display something like this:
## Add a FormGroup ## 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`. 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`: 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. 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` Notice that now the single input is in a `form` element. The `novalidate`
attribute in the `<form>` element prevents the browser attribute in the `<form>` element prevents the browser
from attempting native HTML validations. from attempting native HTML validations.
`formGroup` is a reactive form directive that takes an existing `formGroup` is a reactive form directive that takes an existing
`FormGroup` instance and associates it with an HTML element. `FormGroup` instance and associates it with an HTML element.
In this case, it associates the `FormGroup` you saved as In this case, it associates the `FormGroup` you saved as
`heroForm` with the form element. `heroForm` with the form element.
Because the class now has a `FormGroup`, you must update the template Because the class now has a `FormGroup`, you must update the template
syntax for associating the input with the corresponding syntax for associating the input with the corresponding
`FormControl` in the component class. `FormControl` in the component class.
Without a parent `FormGroup`, Without a parent `FormGroup`,
`[formControl]="name"` worked earlier because that directive `[formControl]="name"` worked earlier because that directive
can stand alone, that is, it works without being in a `FormGroup`. can stand alone, that is, it works without being in a `FormGroup`.
With a parent `FormGroup`, the `name` input needs the syntax With a parent `FormGroup`, the `name` input needs the syntax
`formControlName=name` in order to be associated `formControlName=name` in order to be associated
with the correct `FormControl` with the correct `FormControl`
in the class. This syntax tells Angular to look for the parent in the class. This syntax tells Angular to look for the parent
`FormGroup`, in this case `heroForm`, and then _inside_ that group `FormGroup`, in this case `heroForm`, and then _inside_ that group
to look for a `FormControl` called `name`. 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>, <a href="http://getbootstrap.com/" title="Bootstrap CSS">Bootstrap CSS library</a>,
not Angular. 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. 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? The form looks great. But does it work?
When the user enters a name, where does the value go? When the user enters a name, where does the value go?
{@a json} {@a json}
@ -442,7 +442,7 @@ When the user enters a name, where does the value go?
## Taking a look at the form model ## Taking a look at the form model
The value goes into the **_form model_** that backs the group's `FormControls`. 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`: 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'> <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> </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. 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. `FormBuilder` makes form development and maintenance easier.
@ -481,8 +481,8 @@ In real life apps, forms get big fast.
## Introduction to _FormBuilder_ ## Introduction to _FormBuilder_
The `FormBuilder` class helps reduce repetition and The `FormBuilder` class helps reduce repetition and
clutter by handling details of control creation for you. clutter by handling details of control creation for you.
To use `FormBuilder`, you need to import it into `hero-detail.component.ts`: 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` 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. 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. 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 ### Validators.required
Though this guide doesn't go deeply into validations, here is one example that Though this guide doesn't go deeply into validations, here is one example that
demonstrates the simplicity of using `Validators.required` in reactive forms. demonstrates the simplicity of using `Validators.required` in reactive forms.
First, import the `Validators` symbol. First, import the `Validators` symbol.
@ -531,8 +531,8 @@ First, import the `Validators` symbol.
To make the `name` `FormControl` required, replace the `name` To make the `name` `FormControl` required, replace the `name`
property in the `FormGroup` with an array. property in the `FormGroup` with an array.
The first item is the initial value for `name`; The first item is the initial value for `name`;
the second is the required validator, `Validators.required`. 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. 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> </div>
@ -567,29 +567,29 @@ The browser displays the following:
<figure class='image-display'> <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> </figure>
`Validators.required` is working. The status is `INVALID` because the input box has no value. `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. 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. It remains in each of the following examples with the same configuration.
For more on validating Angular forms, see the For more on validating Angular forms, see the
[Form Validation](cookbook/form-validation) guide. [Form Validation](cookbook/form-validation) guide.
### More FormControls ### More FormControls
A hero has more than a name. A hero has more than a name.
A hero has an address, a super power and sometimes a sidekick too. 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`. 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"> <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"> <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. 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. `form-control`, `center-block`, and `checkbox` in this markup.
Those are _bootstrap_ CSS classes that Angular itself ignores. Those are _bootstrap_ CSS classes that Angular itself ignores.
Pay attention to the `formGroupName` and `formControlName` attributes. 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. 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`, The revised template includes more text inputs, a select box for the `state`, radio buttons for the `power`,
and a checkbox for the `sidekick`. 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. 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. 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 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, You tie these controls to the template HTML elements in the same way,
specifiying the `FormControl` name with the `formControlName` directive. specifiying the `FormControl` name with the `formControlName` directive.
See the API reference for more information about See the API reference for more information about
[radio buttons](api/forms/index/RadioControlValueAccessor-directive "API: RadioControlValueAccessor"), [radio buttons](api/forms/index/RadioControlValueAccessor-directive "API: RadioControlValueAccessor"),
[selects](api/forms/index/SelectControlValueAccessor-directive "API: SelectControlValueAccessor"), and [selects](api/forms/index/SelectControlValueAccessor-directive "API: SelectControlValueAccessor"), and
[checkboxes](api/forms/index/CheckboxControlValueAccessor-directive "API: CheckboxControlValueAccessor"). [checkboxes](api/forms/index/CheckboxControlValueAccessor-directive "API: CheckboxControlValueAccessor").
@ -656,12 +656,12 @@ See the API reference for more information about
### Nested FormGroups ### Nested FormGroups
This form is getting big and unwieldy. You can group some of the related `FormControls` 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 into a nested `FormGroup`. The `street`, `city`, `state`, and `zip` are properties
that would make a good _address_ `FormGroup`. that would make a good _address_ `FormGroup`.
Nesting groups and controls in this way allows you to Nesting groups and controls in this way allows you to
mirror the hierarchical structure of the data model mirror the hierarchical structure of the data model
and helps track validation and state for related sets of controls. and helps track validation and state for related sets of controls.
You used the `FormBuilder` to create one `FormGroup` in this component called `heroForm`. You used the `FormBuilder` to create one `FormGroup` in this component called `heroForm`.
Let that be the parent `FormGroup`. 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. you must make corresponding adjustments to the component template.
In `hero-detail.component.html`, wrap the address-related `FormControls` in a `div`. 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"`. 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`. 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: 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_ 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'> <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> </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. 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`. 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 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 You can do this _within_ the component class or display it on the
page by adding the following to the template, page by adding the following to the template,
immediately after the `{{form.value | json}}` interpolation as follows: 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"> <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: such as one of the following:
<style> <style>
@ -788,7 +788,7 @@ such as one of the following:
<td> <td>
the validity of a `FormControl`. Possible values: `VALID`, the validity of a `FormControl`. Possible values: `VALID`,
`INVALID`, `PENDING`, or `DISABLED`. `INVALID`, `PENDING`, or `DISABLED`.
</td> </td>
@ -820,7 +820,7 @@ such as one of the following:
`true` if the control user has not yet entered the HTML control `true` if the control user has not yet entered the HTML control
and triggered its blur event. Its opposite is `myControl.touched`. and triggered its blur event. Its opposite is `myControl.touched`.
</td> </td>
</tr> </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. [_AbstractControl_](api/forms/index/AbstractControl-class) API reference.
One common reason for inspecting `FormControl` properties is to One common reason for inspecting `FormControl` properties is to
make sure the user entered valid values. make sure the user entered valid values.
Read more about validating Angular forms in the Read more about validating Angular forms in the
[Form Validation](cookbook/form-validation) guide. [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_. The component must copy the hero values in the _data model_ into the _form model_.
There are two important implications: 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_. 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_. 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_ ## Populate the form model with _setValue_ and _patchValue_
Previously you created a control and initialized its value at the same time. Previously you created a control and initialized its value at the same time.
You can also initialize or reset the values _later_ with the You can also initialize or reset the values _later_ with the
`setValue` and `patchValue` methods. `setValue` and `patchValue` methods.
### _setValue_ ### _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. 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 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 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. error messages if you have a typo or if you've nested controls incorrectly.
`patchValue` will fail silently. `patchValue` will fail silently.
On the other hand,`setValue` will catch On the other hand,`setValue` will catch
the error and report it clearly. the error and report it clearly.
Notice that you can _almost_ use the entire `hero` as the argument to `setValue` 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. 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_ ### _patchValue_
With **`patchValue`**, you can assign values to specific controls in a `FormGroup` 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. 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. 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. values and does not throw helpful errors.
### When to set form model values (_ngOnChanges_) ### 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. every time the user selects a new hero.
You should call _setValue_ in the [ngOnChanges](guide/lifecycle-hooks#onchanges) You should call _setValue_ in the [ngOnChanges](guide/lifecycle-hooks#onchanges)
hook, which Angular calls whenever the input `hero` property changes 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 ### _reset_ the form flags
You should reset the form when the hero changes so that You should reset the form when the hero changes so that
control values from the previous hero are cleared and control values from the previous hero are cleared and
status flags are restored to the _pristine_ state. status flags are restored to the _pristine_ state.
You could call `reset` at the top of `ngOnChanges` like this. 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. 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`. Internally, `reset` passes the argument to `setValue`.
A little refactoring and `ngOnChanges` becomes this: 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"> <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'> <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> </figure>
The `HeroListComponent` uses an injected `HeroService` to retrieve heroes from the server 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. and then presents those heroes to the user as a series of buttons.
The `HeroService` emulates an HTTP service. The `HeroService` emulates an HTTP service.
It returns an `Observable` of heroes that resolves after a short delay, It returns an `Observable` of heroes that resolves after a short delay,
both to simulate network latency and to indicate visually both to simulate network latency and to indicate visually
the necessarily asynchronous nature of the application. the necessarily asynchronous nature of the application.
When the user clicks on a hero, 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_ 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"). [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, If you're coding along with the steps in this reactive forms tutorial,
create the pertinent files based on the create the pertinent files based on the
[source code displayed below](guide/reactive-forms#source-code "Reactive Forms source code"). [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`, 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. 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). let the user add or modify addresses (removing addresses is your homework).
Youll need to redefine the form model in the `HeroDetailComponent` constructor, 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"> <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: 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_. 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. But it can be anything that makes sense within the application domain.
_Presentation_ requirements often differ from _data_ requirements. _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`. The current HTML template displays a single _address_ `FormGroup`.
Revise it to display zero, one, or more of the hero's _address_ `FormGroups`. 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`. repeating that `<div>` with `*ngFor`.
The trick lies in knowing how to write the `*ngFor`. There are three key points: 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"`. 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. 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`. 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 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"> <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`. In fact, you should always specify a button's `type`.
Without an explict type, the button type defaults to "submit". 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 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'> <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> </figure>
Click the "_Add a Secret Lair_" button. Click the "_Add a Secret Lair_" button.
A new address section appears. Well done! A new address section appears. Well done!
### Remove a lair ### 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. 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_. 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. that raises a change event.
These are properties, such as `valueChanges`, that return an RxJS `Observable`. 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 ### When to use it
An interpolation binding is the easier way to _display_ a name change. 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. 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'> <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> </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_. 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`) 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"> <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** **Address deep copy**
Had you assigned the `formModel.secretLairs` to `saveHero.addresses` (see line commented out), 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`. as the lairs in the `formModel.secretLairs`.
A user's subsequent changes to a lair street would mutate an address street in the `saveHero`. 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 ### Angulars cross-site scripting security model
To systematically block XSS bugs, Angular treats all values as untrusted by default. When a value 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 sanitizes and escapes untrusted values.
_Angular templates are the same as executable code_: HTML, attributes, and binding expressions _Angular templates are the same as executable code_: HTML, attributes, and binding expressions
(but not the values bound) in templates are trusted to be safe. This means that applications must (but not the values bound) in templates are trusted to be safe. This means that applications must
prevent values that an attacker can control from ever making it into the source code of a 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 To prevent these vulnerabilities, use
the [offline template compiler](guide/security#offline-template-compiler), also known as _template injection_. 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'> <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> </figure>
@ -159,7 +159,7 @@ templates where possible.
Content Security Policy (CSP) is a defense-in-depth Content Security Policy (CSP) is a defense-in-depth
technique to prevent XSS. To enable CSP, configure your web server to return an appropriate 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/) [An Introduction to Content Security Policy](http://www.html5rocks.com/en/tutorials/security/content-security-policy/)
on the HTML5Rocks website. 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, 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 and greatly improves application performance. Use the offline template compiler in production
deployments; don't dynamically generate templates. Angular trusts template code, so generating 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. 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 For information about dynamically constructing forms in a safe way, see the
[Dynamic Forms](cookbook/dynamic-form) cookbook page. [Dynamic Forms](cookbook/dynamic-form) cookbook page.
### Server-side XSS protection ### Server-side XSS protection
HTML constructed on the server is vulnerable to injection attacks. Injecting template code into an 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 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 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 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. 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 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 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 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 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 are introducing a security vulnerability into your application. If in doubt, find a professional
security reviewer. security reviewer.
To mark a value as trusted, inject `DomSanitizer` and call one of the 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'> <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> </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 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 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 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 could execute. So call a method on the controller to construct a trusted video URL, which causes
Angular to allow binding into `<iframe src>`: 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 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. 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 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 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`). to the application's web server (such as `example-bank.com`).
Assume the user is logged into the application at `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. 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. 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. 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`. 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 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. The server and client must cooperate to thwart this attack.
In a common anti-XSRF technique, the application server sends a randomly 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 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. 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. 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. 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. The default `CookieXSRFStrategy` is turned on automatically.
Before sending an HTTP request, the `CookieXSRFStrategy` looks for a cookie called `XSRF-TOKEN` and 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. sets a header named `X-XSRF-TOKEN` with the value of that cookie.
The server must do its part by setting the The server must do its part by setting the
initial `XSRF-TOKEN` cookie and confirming that each subsequent state-modifying request 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 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/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>. <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. <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>. <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>
<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> </td>
</tr> </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: for getting and setting the current HTML document title:
* `getTitle() : string`&mdash;Gets the title of the current HTML document. * `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: 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à! Bind that method to three anchor tags and voilà!
<figure class='image-display'> <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> </figure>
@ -126,8 +126,8 @@ a location you reserve for configuring the runtime Angular environment.
That's exactly what you're doing. That's exactly what you're doing.
The `Title` service is part of the Angular *browser platform*. The `Title` service is part of the Angular *browser platform*.
If you bootstrap your application into a different 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. the concept of a "document title" for that specific platform.
Ideally, the application itself neither knows nor cares about the runtime environment. 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. how you can write your own structural directives to do the same thing.
### Table of contents ### 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 They shape or reshape the DOM's _structure_, typically by adding, removing, or manipulating
elements. 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. The directive then does whatever it's supposed to do with that host element and its descendents.
Structural directives are easy to recognize. Structural directives are easy to recognize.
An asterisk (*) precedes the directive attribute name as in this example. An asterisk (*) precedes the directive attribute name as in this example.
@ -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 and the string is a [_microsyntax_](guide/structural-directives#microsyntax) rather than the usual
[template expression](guide/template-syntax#template-expressions). [template expression](guide/template-syntax#template-expressions).
Angular desugars this notation into a marked-up `<ng-template>` that surrounds the 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. Each structural directive does something different with that template.
Three of the common, built-in structural directives&mdash;[NgIf](guide/template-syntax#ngIf), 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 [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. 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: 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_. Throughout this guide, you'll see a directive spelled in both _UpperCamelCase_ and _lowerCamelCase_.
Already you've seen `NgIf` and `ngIf`. Already you've seen `NgIf` and `ngIf`.
There's a reason. `NgIf` refers to the directive _class_; There's a reason. `NgIf` refers to the directive _class_;
`ngIf` refers to the directive's _attribute name_. `ngIf` refers to the directive's _attribute name_.
A directive _class_ is spelled in _UpperCamelCase_ (`NgIf`). A directive _class_ is spelled in _UpperCamelCase_ (`NgIf`).
A directive's _attribute name_ is spelled in _lowerCamelCase_ (`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. (1)&nbsp;components and (2)&nbsp;attribute directives.
A *component* manages a region of HTML in the manner of a native HTML element. A *component* manages a region of HTML in the manner of a native HTML element.
Technically it's a directive with a template. Technically it's a directive with a template.
An [*attribute* directive](guide/attribute-directives) changes the appearance or behavior An [*attribute* directive](guide/attribute-directives) changes the appearance or behavior
of an element, component, or another directive. 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'> <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> </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)). 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, 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'> <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> </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. It does matter when the host element is attached to a resource intensive component.
Such a component's behavior continues even when hidden. Such a component's behavior continues even when hidden.
The component stays attached to its DOM element. It keeps listening to events. 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. The component doesn't re-initialize&mdash;an operation that could be expensive.
So hiding and showing is sometimes the right thing to do. 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 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` . and recover the unused resources with a structural directive like `NgIf` .
**These same considerations apply to every structural directive, whether built-in or custom.** **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. 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 `*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. * 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. Only the finished product ends up in the DOM.
<figure class='image-display'> <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> </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. 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. 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_ ## Inside _*ngFor_
Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax through Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax through
template _attribute_ to `<ng-template>` _element_. template _attribute_ to `<ng-template>` _element_.
Here's a full-featured application of `NgFor`, written all three ways: Here's a full-featured application of `NgFor`, written all three ways:
@ -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. The `NgFor` directive has more features, both required and optional, than the `NgIf` shown in this guide.
At minimum `NgFor` needs a looping variable (`let hero`) and a list (`heroes`). At minimum `NgFor` needs a looping variable (`let hero`) and a list (`heroes`).
You enable these features in the string assigned to `ngFor`, which you write in Angular's [microsyntax](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"> <div class="alert is-helpful">
Everything _outside_ the `ngFor` string stays with the host element Everything _outside_ the `ngFor` string stays with the host element
(the `<div>`) as it moves inside the `<ng-template>`. (the `<div>`) as it moves inside the `<ng-template>`.
In this example, the `[ngClass]="odd"` stays on the `<div>`. 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 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 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`. 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`. `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`. 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_ . 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`. 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`. * 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. Angular sets them to the current value of the context's `index` and `odd` properties.
* The context property for `let-hero` wasn't specified. * The context property for `let-hero` wasn't specified.
It's intended source is implicit. It's intended source is implicit.
Angular sets `let-hero` to the value of the context's `$implicit` property Angular sets `let-hero` to the value of the context's `$implicit` property
which `NgFor` has initialized with the hero for the current iteration. 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. describes additional `NgFor` directive properties and context properties.
These microsyntax mechanisms are available to you when you write your own structural directives. 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") [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. 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`. There are several such variables in this example: `hero`, `i`, and `odd`.
All are preceded by the keyword `let`. All are preceded by the keyword `let`.
A _template input variable_ is **_not_** the same as a A _template input variable_ is **_not_** the same as a
[template _reference_ variable](guide/template-syntax#ref-vars), [template _reference_ variable](guide/template-syntax#ref-vars),
neither _semantically_ nor _syntactically_. 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. The variable's scope is limited to a _single instance_ of the repeated template.
You can use the same variable name again in the definition of other structural directives. You can use the same variable name again in the definition of other structural directives.
@ -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. 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. 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. 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`? 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? 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 The switch value assigned to `NgSwitch` (`hero.emotion`) determines which
(if any) of the switch cases are displayed. (if any) of the switch cases are displayed.
`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. It's an _attribute_ directive that controls the behavior of the other two switch directives.
That's why you write `[ngSwitch]`, never `*ngSwitch`. That's why you write `[ngSwitch]`, never `*ngSwitch`.
`NgSwitchCase` and `NgSwitchDefault` _are_ structural directives. `NgSwitchCase` and `NgSwitchDefault` _are_ structural directives.
You attach them to elements using the asterisk (*) prefix notation. You attach them to elements using the asterisk (*) prefix notation.
An `NgSwitchCase` displays its host element when its value matches the switch value. An `NgSwitchCase` displays its host element when its value matches the switch value.
The `NgSwitchDefault` displays its host element when no sibling `NgSwitchCase` matches the switch value. The `NgSwitchDefault` displays its host element when no sibling `NgSwitchCase` matches the switch value.
@ -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 `<happy-hero>` is the host element for the happy `*ngSwitchCase`.
The `<unknown-hero>` is the host element for the `*ngSwitchDefault`. The `<unknown-hero>` is the host element for the `*ngSwitchDefault`.
@ -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. 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;*
The &lt;ng-template&gt; is an Angular element for rendering HTML. 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. 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>`, 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'> <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> </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 Introducing another container element&mdash;typically a `<span>` or `<div>`&mdash;to
group the elements under a single _root_ is usually harmless. group the elements under a single _root_ is usually harmless.
_Usually_ ... but not _always_. _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. neither expect nor accommodate the new layout.
For example, suppose you have the following paragraph layout. For example, suppose you have the following paragraph layout.
@ -564,7 +564,7 @@ The constructed paragraph renders strangely.
<figure class='image-display'> <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> </figure>
@ -572,7 +572,7 @@ The constructed paragraph renders strangely.
The `p span` style, intended for use elsewhere, was inadvertently applied here. 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. 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>`. You can't wrap the _options_ in a conditional `<div>` or a `<span>`.
When you try this, When you try this,
@ -588,7 +588,7 @@ the drop down is empty.
<figure class='image-display'> <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> </figure>
@ -598,7 +598,7 @@ The browser won't display an `<option>` within a `<span>`.
### &lt;ng-container&gt; to the rescue ### &lt;ng-container&gt; to the rescue
The Angular `<ng-container>` is a grouping element that doesn't interfere with styles or layout 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>`. Here's the conditional paragraph again, this time using `<ng-container>`.
@ -613,7 +613,7 @@ It renders properly.
<figure class='image-display'> <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> </figure>
@ -631,13 +631,13 @@ The drop down works properly.
<figure class='image-display'> <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> </figure>
The `<ng-container>` is a syntax element recognized by the Angular parser. 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: 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; statement1;
statement2; statement2;
statement3; statement3;
} }
</code-example> </code-example>
@ -709,9 +709,9 @@ Angular's own directives do not.
### _TemplateRef_ and _ViewContainerRef_ ### _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") [_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") [_view container_](api/core/index/ViewContainerRef-class "API: ViewContainerRef")
adjacent to the directive's original `<p>` host element. 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 _myUnless_ property
The directive consumer expects to bind a true/false condition to `[myUnless]`. The directive consumer expects to bind a true/false condition to `[myUnless]`.
That means the directive needs a `myUnless` property, decorated with `@Input` That means the directive needs a `myUnless` property, decorated with `@Input`
<div class="l-sub-section"> <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, * 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. 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. clear the container which also destroys the view.
Nobody reads the `myUnless` property so it doesn't need a getter. Nobody reads the `myUnless` property so it doesn't need a getter.
@ -788,7 +788,7 @@ When the `condition` is truthy, the top (A) paragraph is removed and the bottom
<figure class='image-display'> <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> </figure>
@ -799,7 +799,7 @@ When the `condition` is truthy, the top (A) paragraph is removed and the bottom
## Summary ## Summary
You can both try and download the source code for this guide in the <live-example></live-example>. You can both try and download the source code for this guide in the <live-example></live-example>.
Here is the source from the `src/app/` folder. 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. 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. 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 in templates
HTML is the language of the Angular template. HTML is the language of the Angular template.
Almost all HTML syntax is valid template syntax. Almost all HTML syntax is valid template syntax.
The `<script>` element is a notable exception; The `<script>` element is a notable exception;
it is forbidden, eliminating the risk of script injection attacks. it is forbidden, eliminating the risk of script injection attacks.
In practice, `<script>` is ignored and a warning appears in the browser console. In practice, `<script>` is ignored and a warning appears in the browser console.
See the [Security](guide/security) page for details. See the [Security](guide/security) page for details.
Some legal HTML doesn't make much sense in a template. Some legal HTML doesn't make much sense in a template.
The `<html>`, `<body>`, and `<base>` elements have no useful role. The `<html>`, `<body>`, and `<base>` elements have no useful role.
Pretty much everything else is fair game. 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. 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. 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'> <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> </figure>
@ -1837,7 +1837,7 @@ Here are all variations in action, including the uppercase version:
<figure class='image-display'> <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> </figure>
@ -2132,7 +2132,7 @@ Here is an illustration of the _trackBy_ effect.
<figure class='image-display'> <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> </figure>
@ -2167,7 +2167,7 @@ Angular puts only the *selected* element into the DOM.
<figure class='image-display'> <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> </figure>
@ -2417,7 +2417,7 @@ The terms _input_ and _output_ reflect the perspective of the target directive.
<figure class='image-display'> <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> </figure>
@ -2669,5 +2669,5 @@ It works perfectly with long property paths such as `a?.b?.c?.d`.
## Summary ## 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. 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. After a few moments, karma opens a browser and starts writing to the console.
<figure class='image-display'> <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> </figure>
@ -473,7 +473,7 @@ Debug specs in the browser in the same way that you debug an application.
<figure class='image-display'> <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> </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. The `HeroDetailComponent` is a simple view with a title, two hero fields, and two buttons.
<figure class='image-display'> <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> </figure>
@ -2505,7 +2505,7 @@ A better solution is to create an artificial test component that demonstrates al
<figure class='image-display'> <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> </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 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_. by flushing both _timer_ and _micro-task_ queues within the _fakeAsync test zone_.
<div class="l-sub-section"> <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, The curious, dedicated reader might enjoy this lengthy blog post,
"<a href="https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/" "<a href="https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/"
>_Tasks, microtasks, queues and schedules_</a>". >_Tasks, microtasks, queues and schedules_</a>".
</div> </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`. The immediate `DebugElement` children. Walk the tree by descending through `children`.
<div class="l-sub-section"> <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` also has `childNodes`, a list of `DebugNode` objects.
`DebugElement` derives from `DebugNode` objects and there are often `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> </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. _Angular_ is the name for the Angular of today and tomorrow.
_AngularJS_ is the name for all v1.x versions of Angular. _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. Always consider the business case before moving to Angular.
An important part of that case is the time and effort to get there. 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 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'> <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> </figure>
@ -381,7 +381,7 @@ ways:
<figure class='image-display'> <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> </figure>
@ -435,7 +435,7 @@ AngularJS and Angular approaches. Here's what happens:
<figure class='image-display'> <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> </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. 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. 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. 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. Now we bootstrap `AppModule` using `platformBrowserDynamic`'s `bootstrapModule` method.
Then we use dependency injection to get a hold of the `UpgradeModule` instance in `AppModule`, 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): 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` 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)"> <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 ### Using Angular Components from AngularJS Code
<figure> <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> </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`. `declarations` in the `AppModule`.
And because this component is being used from the AngularJS module, and is an entry point into 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 our Angular application, we also need to add it to the `entryComponents` for our
Angular module. Angular module.
@ -661,7 +661,7 @@ like this:
These inputs and outputs can be supplied from the AngularJS template, and the 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: 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 ### Using AngularJS Component Directives from Angular Code
<figure> <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> </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 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. 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. 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 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 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 component is just a directive - a tag - and Angular doesn't have to concern itself with
it's children. it's children.
</div> </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: 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 ### Projecting AngularJS Content into Angular Components
<figure> <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> </figure>
@ -983,7 +983,7 @@ remains in "AngularJS land" and is managed by the AngularJS framework.
### Transcluding Angular Content into AngularJS Component Directives ### Transcluding Angular Content into AngularJS Component Directives
<figure> <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> </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) 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 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 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 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"> <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()`. Now wrap the Angular `Heroes` in an *AngularJS factory function* using `downgradeInjectable()`.
and plug the factory into an AngularJS module. and plug the factory into an AngularJS module.
The name of the AngularJS dependency is up to you: 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 We can take advantage of Ahead-of-time (AoT) compilation on hybrid apps just like on any other
Angular application. 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) [the Ahead-of-time Compilation chapter](guide/aot-compiler)
save for differences in `index.html` and `main-aot.ts` 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 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. 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: 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, 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 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. on the upgraded component class and forward them to the `UpgradeComponent` parent.
</div> </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. 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 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`. 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"> <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)"> <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. 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 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 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. 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 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. 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 Take a look at the results of the [Setup](guide/setup) instructions
and get the following configurations from there: 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 We also need to make a couple of adjustments
to the `systemjs.config.js` file installed during [setup](guide/setup). 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, We want to point the browser to the project root when loading things through SystemJS,
instead of using the `<base>` URL. instead of using the `<base>` URL.
We also need to install the `upgrade` package via `npm install @angular/upgrade --save` 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"> <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_ ### Creating the _AppModule_
Now create the root `NgModule` class called `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. Rename it to `app.module.ajs.ts` and update the corresponding script name in the `index.html` as well.
The file contents remain: 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 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 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`. 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. 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_? #### 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> <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 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. 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 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. 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 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. loaded correctly.
This is a considerable effort and it often isn't worth it, especially since we are in the 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. process of moving our our to Angular already.
Instead we declare `angular` as `angular.IAngularStatic` to indicate it is a global variable Instead we declare `angular` as `angular.IAngularStatic` to indicate it is a global variable
and still have full typing support. 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. * For loading the details of a single phone into the phone detail component.
We can replace this implementation with an Angular service class, while 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`. 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 We need to do this for all RxJS operators that we want to use, since Angular
does not load all of them by default. 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: 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). [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. 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 #### No Angular _filter_ or _orderBy_ filters
The built-in AngularJS `filter` and `orderBy` filters do not exist in Angular, 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, 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"> <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. 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*, Instead of registering a component, we register a `phoneList` *directive*,
a downgraded version of the Angular component. a downgraded version of the Angular component.
The `as angular.IDirectiveFactory` cast tells the TypeScript compiler 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 Add the `FormsModule` to `NgModule` imports, declare the new `PhoneListComponent` and
finally add it to `entryComponents` since we downgraded it: 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. This is similar to the phone list component.
The new wrinkle is the `RouteParams` type annotation that identifies the `routeParams` dependency. The new wrinkle is the `RouteParams` type annotation that identifies the `routeParams` dependency.
The AngularJS injector has an AngularJS router dependency called `$routeParams`, The AngularJS injector has an AngularJS router dependency called `$routeParams`,
which was injected into `PhoneDetails` when it was still an AngularJS controller. 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. There is no upgrade method to convert filters into pipes.
You won't miss it. 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. The implementation is the same as before, repackaged in the `transform` method.
Rename the file to `checkmark.pipe.ts` to conform with Angular conventions: 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, 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). 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`: 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 Most AngularJS apps have more than a couple of routes though, and it's very helpful to migrate
one route at a time. 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. while keeping `/phones/:phoneId` in the AngularJS router.
#### Add the Angular 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. 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* 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. 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: 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. and `ng-view` for AngularJS routes.
This component just renders the contents of the active route and nothing else. 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. element on the host web page when the application launches.
Add this `<phonecat-app>` element to the `index.html`. 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_ #### Create the _Routing Module_
A router needs configuration whether it's the AngularJS or Angular or any other router. 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 which recommends that you create a `NgModule` dedicated to router configuration
(called a _Routing Module_). (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 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. 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. instead of the default "push state" strategy.
There's a twist to our Routing Module though: we're also adding a custom `UrlHandlingStrategy` 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 Now update the `AppModule` to import this `AppRoutingModule` and also the
declare the root `AppComponent` as the bootstrap component. 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. insert it's view into the host web page.
We can also remove the `ngDoBootstrap()` override from `app.module.ts` since we are now 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 #### 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 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`: 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. 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 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"> <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. The application is still bootstrapped as a hybrid app.
There's no need for that anymore. There's no need for that anymore.
Switch the bootstrap method of the application from the `UpgradeAdapter` Switch the bootstrap method of the application from the `UpgradeAdapter`
to the Angular way. to the Angular way.
<code-example path="upgrade-phonecat-4-final/app/main.ts" title="main.ts"> <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`, 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) 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. 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. 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 Since we have no downgraded components anymore, we also don't need to have them listed
in `entryComponents` either. 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. 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. 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: 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. 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 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 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`: 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 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 (|). in the component's `values` property, followed by a separator character (|).
The [interpolation](guide/template-syntax#interpolation) 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. Suppose the user enters the letters "abc", and then backspaces to remove them one by one.
Here's what the UI displays: Here's what the UI displays:
@ -98,7 +98,7 @@ Here's what the UI displays:
<figure class='image-display'> <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> </figure>
@ -127,7 +127,7 @@ for `event.target.value` in which case the same user input would produce:
### Type the _$event_ ### Type the _$event_
The example above casts the `$event` as an `any` type. 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 There is no type information
that could reveal properties of the event object and prevent silly mistakes. 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. 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. 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: 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. 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. 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_). and the component (_how the application processes user data_).
The next section shows how to use template reference variables to address this problem. 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'> <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> </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) Angular updates the bindings (and therefore the screen)
only if the app does something in response to asynchronous events, such as keystrokes. only if the app does something in response to asynchronous events, such as keystrokes.
This example code binds the `keyup` event This example code binds the `keyup` event
to the number 0, the shortest template statement possible. to the number 0, the shortest template statement possible.
While the statement does nothing useful, While the statement does nothing useful,
it satisfies Angular's requirement so that Angular will update the screen. it satisfies Angular's requirement so that Angular will update the screen.
</div> </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. 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_. 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_. 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"> <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. Here's how it works.
<figure class='image-display'> <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> </figure>
@ -269,7 +269,7 @@ clicking **Add**.
<figure class='image-display'> <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> </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 Two-way data binding is a more elegant and compact way to move
values between data entry fields and model properties. values between data entry fields and model properties.
The next page, `Forms`, explains how to write 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