fix(docs-infra): rename "title" by "header" to avoid unwanted tooltips (#26396)

Closes #26174

PR Close #26396
This commit is contained in:
William Marques 2018-10-11 13:29:59 +02:00 committed by Misko Hevery
parent ecd473bbce
commit fc6dad40ac
74 changed files with 1281 additions and 1281 deletions

View File

@ -202,10 +202,10 @@ The following are some of the key AngularJS built-in directives and their equiva
### Bootstrapping ### Bootstrapping
<code-example hideCopy path="ajs-quick-reference/src/main.ts" title="main.ts" linenums="false"></code-example> <code-example hideCopy path="ajs-quick-reference/src/main.ts" header="main.ts" linenums="false"></code-example>
<br> <br>
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" title="app.module.ts" linenums="false"></code-example> <code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" header="app.module.ts" linenums="false"></code-example>
Angular doesn't have a bootstrap directive. Angular doesn't have a bootstrap directive.

View File

@ -37,7 +37,7 @@ To get started with adding Angular animations to your project, import the animat
Import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module. Import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
<code-example path="animations/src/app/app.module.1.ts" title="src/app/app.module.ts" language="typescript" linenums="false"> <code-example path="animations/src/app/app.module.1.ts" header="src/app/app.module.ts" language="typescript" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -49,7 +49,7 @@ Import `BrowserAnimationsModule`, which introduces the animation capabilities in
If you plan to use specific animation functions in component files, import those functions from `@angular/animations`. If you plan to use specific animation functions in component files, import those functions from `@angular/animations`.
<code-example path="animations/src/app/app.component.ts" title="src/app/app.component.ts" region="imports" language="typescript"> <code-example path="animations/src/app/app.component.ts" header="src/app/app.component.ts" region="imports" language="typescript">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -61,7 +61,7 @@ If you plan to use specific animation functions in component files, import those
In the component file, add a metadata property called `animations:` within the `@Component()` decorator. You put the trigger that defines an animation within the `animations` metadata property. In the component file, add a metadata property called `animations:` within the `@Component()` decorator. You put the trigger that defines an animation within the `animations` metadata property.
<code-example path="animations/src/app/app.component.ts" title="src/app/app.component.ts" region="decorator" language="typescript"> <code-example path="animations/src/app/app.component.ts" header="src/app/app.component.ts" region="decorator" language="typescript">
</code-example> </code-example>
## Animating a simple transition ## Animating a simple transition
@ -82,12 +82,12 @@ Use the `style()` function to define a set of styles to associate with a given s
Let's see how Angular's `state()` function works with the `style­()` function to set CSS style attributes. In this code snippet, multiple style attributes are set at the same time for the state. In the `open` state, the button has a height of 200 pixels, an opacity of 1, and a background color of yellow. Let's see how Angular's `state()` function works with the `style­()` function to set CSS style attributes. In this code snippet, multiple style attributes are set at the same time for the state. In the `open` state, the button has a height of 200 pixels, an opacity of 1, and a background color of yellow.
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" region="state1" language="typescript"> <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" region="state1" language="typescript">
</code-example> </code-example>
In the `closed` state, shown below, the button has a height of 100 pixels, an opacity of 0.5, and a background color of green. In the `closed` state, shown below, the button has a height of 100 pixels, an opacity of 0.5, and a background color of green.
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" region="state2" language="typescript"> <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" region="state2" language="typescript">
</code-example> </code-example>
### Transitions and timing ### Transitions and timing
@ -134,7 +134,7 @@ The third argument, `easing`, controls how the animation [accelerates and decele
This example provides a state transition from `open` to `closed` with a one second transition between states. This example provides a state transition from `open` to `closed` with a one second transition between states.
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" language="typescript" <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript"
region="transition1"> region="transition1">
</code-example> </code-example>
@ -142,7 +142,7 @@ In the code snippet above, the `=>` operator indicates unidirectional transition
This example adds a state transition from the `closed` state to the `open` state with a 0.5 second transition animation arc. This example adds a state transition from the `closed` state to the `open` state with a 0.5 second transition animation arc.
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" language="typescript" <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript"
region="transition2"> region="transition2">
</code-example> </code-example>
@ -180,7 +180,7 @@ In this example, we'll name the trigger `openClose`, and attach it to the `butto
Animations are defined in the metadata of the component that controls the HTML element to be animated. Put the code that defines your animations under the `animations:` property within the `@Component()` decorator. Animations are defined in the metadata of the component that controls the HTML element to be animated. Put the code that defines your animations under the `animations:` property within the `@Component()` decorator.
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" language="typescript" <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript"
region="component" linenums="false"> region="component" linenums="false">
</code-example> </code-example>
@ -194,7 +194,7 @@ The animation is executed or triggered when the expression value changes to a ne
The following code snippet binds the trigger to the value of the `isOpen` property. The following code snippet binds the trigger to the value of the `isOpen` property.
<code-example path="animations/src/app/open-close.component.1.html" title="src/app/open-close.component.html" <code-example path="animations/src/app/open-close.component.1.html" header="src/app/open-close.component.html"
region="compare"> region="compare">
</code-example> </code-example>
@ -216,15 +216,15 @@ Here are the code files discussed in the transition example.
<code-tabs> <code-tabs>
<code-pane title="src/app/open-close.component.ts" path="animations/src/app/open-close.component.ts" language="typescript" <code-pane header="src/app/open-close.component.ts" path="animations/src/app/open-close.component.ts" language="typescript"
region="component"> region="component">
</code-pane> </code-pane>
<code-pane title="src/app/open-close.component.html" path="animations/src/app/open-close.component.1.html" <code-pane header="src/app/open-close.component.html" path="animations/src/app/open-close.component.1.html"
region="trigger"> region="trigger">
</code-pane> </code-pane>
<code-pane title="src/app/open-close.component.css" path="animations/src/app/open-close.component.css"> <code-pane header="src/app/open-close.component.css" path="animations/src/app/open-close.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>

View File

@ -15,7 +15,7 @@ Its `selectHero()` method sets a `selectedHero` property when the user clicks to
The component acquires the heroes from a service, which is a TypeScript [parameter property](http://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties) on the constructor. The component acquires the heroes from a service, which is a TypeScript [parameter property](http://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties) on the constructor.
The service is provided to the component through the dependency injection system. The service is provided to the component through the dependency injection system.
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (class)" region="class"></code-example> <code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (class)" region="class"></code-example>
Angular creates, updates, and destroys components as the user moves through the application. Your app can take action at each moment in this lifecycle through optional [lifecycle hooks](guide/lifecycle-hooks), like `ngOnInit()`. Angular creates, updates, and destroys components as the user moves through the application. Your app can take action at each moment in this lifecycle through optional [lifecycle hooks](guide/lifecycle-hooks), like `ngOnInit()`.
@ -31,7 +31,7 @@ In addition to containing or pointing to the template, the `@Component` metadata
Here's an example of basic metadata for `HeroListComponent`. Here's an example of basic metadata for `HeroListComponent`.
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example> <code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
This example shows some of the most useful `@Component` configuration options: This example shows some of the most useful `@Component` configuration options:
@ -63,7 +63,7 @@ A template looks like regular HTML, except that it also contains Angular [templa
For example, here is a template for the Tutorial's `HeroListComponent`. For example, here is a template for the Tutorial's `HeroListComponent`.
<code-example path="architecture/src/app/hero-list.component.html" title="src/app/hero-list.component.html"></code-example> <code-example path="architecture/src/app/hero-list.component.html" header="src/app/hero-list.component.html"></code-example>
This template uses typical HTML elements like `<h2>` and `<p>`, and also includes Angular template-syntax elements, `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and `<app-hero-detail>`. The template-syntax elements tell Angular how to render the HTML to the screen, using program logic and data. This template uses typical HTML elements like `<h2>` and `<p>`, and also includes Angular template-syntax elements, `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and `<app-hero-detail>`. The template-syntax elements tell Angular how to render the HTML to the screen, using program logic and data.
@ -87,7 +87,7 @@ The following diagram shows the four forms of data binding markup. Each form has
This example from the `HeroListComponent` template uses three of these forms. This example from the `HeroListComponent` template uses three of these forms.
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" title="src/app/hero-list.component.html (binding)" region="binding"></code-example> <code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" header="src/app/hero-list.component.html (binding)" region="binding"></code-example>
* The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation) * The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation)
displays the component's `hero.name` property value within the `<li>` element. displays the component's `hero.name` property value within the `<li>` element.
@ -101,7 +101,7 @@ Two-way data binding (used mainly in [template-driven forms](guide/forms))
combines property and event binding in a single notation. combines property and event binding in a single notation.
Here's an example from the `HeroDetailComponent` template that uses two-way data binding with the `ngModel` directive. Here's an example from the `HeroDetailComponent` template that uses two-way data binding with the `ngModel` directive.
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example> <code-example path="architecture/src/app/hero-detail.component.html" linenums="false" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
In two-way binding, a data property value flows to the input box from the component as with property binding. In two-way binding, a data property value flows to the input box from the component as with property binding.
The user's changes also flow back to the component, resetting the property to the latest value, The user's changes also flow back to the component, resetting the property to the latest value,
@ -164,7 +164,7 @@ Just as for components, the metadata for a directive associates the decorated cl
*Structural directives* alter layout by adding, removing, and replacing elements in the DOM. *Structural directives* alter layout by adding, removing, and replacing elements in the DOM.
The example template uses two built-in structural directives to add application logic to how the view is rendered. The example template uses two built-in structural directives to add application logic to how the view is rendered.
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" title="src/app/hero-list.component.html (structural)" region="structural"></code-example> <code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" header="src/app/hero-list.component.html (structural)" region="structural"></code-example>
* [`*ngFor`](guide/displaying-data#ngFor) is an iterative; it tells Angular to stamp out one `<li>` per hero in the `heroes` list. * [`*ngFor`](guide/displaying-data#ngFor) is an iterative; it tells Angular to stamp out one `<li>` per hero in the `heroes` list.
* [`*ngIf`](guide/displaying-data#ngIf) is a conditional; it includes the `HeroDetail` component only if a selected hero exists. * [`*ngIf`](guide/displaying-data#ngIf) is a conditional; it includes the `HeroDetail` component only if a selected hero exists.
@ -176,7 +176,7 @@ In templates they look like regular HTML attributes, hence the name.
The `ngModel` directive, which implements two-way data binding, is an example of an attribute directive. `ngModel` modifies the behavior of an existing element (typically `<input>`) by setting its display value property and responding to change events. The `ngModel` directive, which implements two-way data binding, is an example of an attribute directive. `ngModel` modifies the behavior of an existing element (typically `<input>`) by setting its display value property and responding to change events.
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example> <code-example path="architecture/src/app/hero-detail.component.html" linenums="false" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
Angular has more pre-defined directives that either alter the layout structure Angular has more pre-defined directives that either alter the layout structure
(for example, [ngSwitch](guide/template-syntax#ngSwitch)) (for example, [ngSwitch](guide/template-syntax#ngSwitch))

View File

@ -23,7 +23,7 @@ An NgModule is defined by a class decorated with `@NgModule()`. The `@NgModule()
Here's a simple root NgModule definition. Here's a simple root NgModule definition.
<code-example path="architecture/src/app/mini-app.ts" region="module" title="src/app/app.module.ts" linenums="false"></code-example> <code-example path="architecture/src/app/mini-app.ts" region="module" header="src/app/app.module.ts" linenums="false"></code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">

View File

@ -28,11 +28,11 @@ available to components through *dependency injection*.
Here's an example of a service class that logs to the browser console. Here's an example of a service class that logs to the browser console.
<code-example path="architecture/src/app/logger.service.ts" linenums="false" title="src/app/logger.service.ts (class)" region="class"></code-example> <code-example path="architecture/src/app/logger.service.ts" linenums="false" header="src/app/logger.service.ts (class)" region="class"></code-example>
Services can depend on other services. For example, here's a `HeroService` that depends on the `Logger` service, and also uses `BackendService` to get heroes. That service in turn might depend on the `HttpClient` service to fetch heroes asynchronously from a server. Services can depend on other services. For example, here's a `HeroService` that depends on the `Logger` service, and also uses `BackendService` to get heroes. That service in turn might depend on the `HttpClient` service to fetch heroes asynchronously from a server.
<code-example path="architecture/src/app/hero.service.ts" linenums="false" title="src/app/hero.service.ts (class)" region="class"></code-example> <code-example path="architecture/src/app/hero.service.ts" linenums="false" header="src/app/hero.service.ts (class)" region="class"></code-example>
## Dependency injection (DI) ## Dependency injection (DI)
@ -62,7 +62,7 @@ A dependency doesn't have to be a service&mdash;it could be a function, for exam
When Angular creates a new instance of a component class, it determines which services or other dependencies that component needs by looking at the constructor parameter types. For example, the constructor of `HeroListComponent` needs `HeroService`. When Angular creates a new instance of a component class, it determines which services or other dependencies that component needs by looking at the constructor parameter types. For example, the constructor of `HeroListComponent` needs `HeroService`.
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (constructor)" region="ctor"></code-example> <code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (constructor)" region="ctor"></code-example>
When Angular discovers that a component depends on a service, it first checks if the injector has any existing instances of that service. If a requested service instance doesn't yet exist, the injector makes one using the registered provider, and adds it to the injector before returning the service to Angular. When Angular discovers that a component depends on a service, it first checks if the injector has any existing instances of that service. If a requested service instance doesn't yet exist, the injector makes one using the registered provider, and adds it to the injector before returning the service to Angular.
@ -111,6 +111,6 @@ or in the `@NgModule()` or `@Component()` metadata
service with each new instance of that component. service with each new instance of that component.
At the component level, register a service provider in the `providers` property of the `@Component()` metadata. At the component level, register a service provider in the `providers` property of the `@Component()` metadata.
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (component providers)" region="providers"></code-example> <code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (component providers)" region="providers"></code-example>
For more detailed information, see the [Dependency Injection](guide/dependency-injection) section. For more detailed information, see the [Dependency Injection](guide/dependency-injection) section.

View File

@ -37,7 +37,7 @@ This page demonstrates building a simple _appHighlight_ attribute
directive to set an element's background color directive to set an element's background color
when the user hovers over that element. You can apply it like this: when the user hovers over that element. You can apply it like this:
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" title="src/app/app.component.html (applied)" region="applied"></code-example> <code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" header="src/app/app.component.html (applied)" region="applied"></code-example>
{@a write-directive} {@a write-directive}
@ -59,7 +59,7 @@ _Directives_ must be declared in [Angular Modules](guide/ngmodules) in the same
The generated `src/app/highlight.directive.ts` is as follows: The generated `src/app/highlight.directive.ts` is as follows:
<code-example path="attribute-directives/src/app/highlight.directive.0.ts" title="src/app/highlight.directive.ts"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.0.ts" header="src/app/highlight.directive.ts"></code-example>
The imported `Directive` symbol provides Angular the `@Directive` decorator. The imported `Directive` symbol provides Angular the `@Directive` decorator.
@ -92,7 +92,7 @@ Exporting `HighlightDirective` makes the directive accessible.
Now edit the generated `src/app/highlight.directive.ts` to look as follows: Now edit the generated `src/app/highlight.directive.ts` to look as follows:
<code-example path="attribute-directives/src/app/highlight.directive.1.ts" title="src/app/highlight.directive.ts"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.1.ts" header="src/app/highlight.directive.ts"></code-example>
The `import` statement specifies an additional `ElementRef` symbol from the Angular `core` library: The `import` statement specifies an additional `ElementRef` symbol from the Angular `core` library:
@ -111,7 +111,7 @@ This first implementation sets the background color of the host element to yello
To use the new `HighlightDirective`, add a paragraph (`<p>`) element to the template of the root `AppComponent` and apply the directive as an attribute. To use the new `HighlightDirective`, add a paragraph (`<p>`) element to the template of the root `AppComponent` and apply the directive as an attribute.
<code-example path="attribute-directives/src/app/app.component.1.html" title="src/app/app.component.html" region="applied"></code-example> <code-example path="attribute-directives/src/app/app.component.1.html" header="src/app/app.component.html" region="applied"></code-example>
Now run the application to see the `HighlightDirective` in action. Now run the application to see the `HighlightDirective` in action.
@ -136,12 +136,12 @@ and respond by setting or clearing the highlight color.
Begin by adding `HostListener` to the list of imported symbols. Begin by adding `HostListener` to the list of imported symbols.
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (imports)" region="imports"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
Then add two eventhandlers that respond when the mouse enters or leaves, Then add two eventhandlers that respond when the mouse enters or leaves,
each adorned by the `HostListener` decorator. each adorned by the `HostListener` decorator.
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (mouse-methods)" region="mouse-methods"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (mouse-methods)" region="mouse-methods"></code-example>
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.
@ -162,11 +162,11 @@ The handlers delegate to a helper method that sets the color on the host DOM ele
The helper method, `highlight`, was extracted from the constructor. The helper method, `highlight`, was extracted from the constructor.
The revised constructor simply declares the injected `el: ElementRef`. The revised constructor simply declares the injected `el: ElementRef`.
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (constructor)" region="ctor"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (constructor)" region="ctor"></code-example>
Here's the updated directive in full: Here's the updated directive in full:
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" title="src/app/highlight.directive.ts"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts"></code-example>
Run the app and confirm that the background color appears when Run the app and confirm that the background color appears when
the mouse hovers over the `p` and disappears as it moves out. the mouse hovers over the `p` and disappears as it moves out.
@ -183,11 +183,11 @@ Currently the highlight color is hard-coded _within_ the directive. That's infle
In this section, you give the developer the power to set the highlight color while applying the directive. In this section, you give the developer the power to set the highlight color while applying the directive.
Begin by adding `Input` to the list of symbols imported from `@angular/core`. Begin by adding `Input` to the list of symbols imported from `@angular/core`.
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" title="src/app/highlight.directive.ts (imports)" region="imports"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
Add a `highlightColor` property to the directive class like this: Add a `highlightColor` property to the directive class like this:
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (highlightColor)" region="color"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (highlightColor)" region="color"></code-example>
{@a input} {@a input}
@ -200,19 +200,19 @@ Without that input metadata, Angular rejects the binding; see [below](guide/attr
Try it by adding the following directive binding variations to the `AppComponent` template: Try it by adding the following directive binding variations to the `AppComponent` template:
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" title="src/app/app.component.html (excerpt)" region="color-1"></code-example> <code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" header="src/app/app.component.html (excerpt)" region="color-1"></code-example>
Add a `color` property to the `AppComponent`. Add a `color` property to the `AppComponent`.
<code-example path="attribute-directives/src/app/app.component.1.ts" linenums="false" title="src/app/app.component.ts (class)" region="class"></code-example> <code-example path="attribute-directives/src/app/app.component.1.ts" linenums="false" header="src/app/app.component.ts (class)" region="class"></code-example>
Let it control the highlight color with a property binding. Let it control the highlight color with a property binding.
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" title="src/app/app.component.html (excerpt)" region="color-2"></code-example> <code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" header="src/app/app.component.html (excerpt)" region="color-2"></code-example>
That's good, but it would be nice to _simultaneously_ apply the directive and set the color _in the same attribute_ like this. That's good, but it would be nice to _simultaneously_ apply the directive and set the color _in the same attribute_ like this.
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (color)" region="color"></code-example> <code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
The `[appHighlight]` attribute binding both applies the highlighting directive to the `<p>` element The `[appHighlight]` attribute binding both applies the highlighting directive to the `<p>` element
and sets the directive's highlight color with a property binding. and sets the directive's highlight color with a property binding.
@ -221,7 +221,7 @@ That's a crisp, compact syntax.
You'll have to rename the directive's `highlightColor` property to `appHighlight` because that's now the color property binding name. You'll have to rename the directive's `highlightColor` property to `appHighlight` because that's now the color property binding name.
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (renamed to match directive selector)" region="color-2"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (renamed to match directive selector)" region="color-2"></code-example>
This is disagreeable. The word, `appHighlight`, is a terrible property name and it doesn't convey the property's intent. This is disagreeable. The word, `appHighlight`, is a terrible property name and it doesn't convey the property's intent.
@ -233,23 +233,23 @@ Fortunately you can name the directive property whatever you want _and_ **_alias
Restore the original property name and specify the selector as the alias in the argument to `@Input`. Restore the original property name and specify the selector as the alias in the argument to `@Input`.
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (color property with alias)" region="color"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (color property with alias)" region="color"></code-example>
_Inside_ the directive the property is known as `highlightColor`. _Inside_ the directive the property is known as `highlightColor`.
_Outside_ the directive, where you bind to it, it's known as `appHighlight`. _Outside_ the directive, where you bind to it, it's known as `appHighlight`.
You get the best of both worlds: the property name you want and the binding syntax you want: You get the best of both worlds: the property name you want and the binding syntax you want:
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (color)" region="color"></code-example> <code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
Now that you're binding via the alias to the `highlightColor`, modify the `onMouseEnter()` method to use that property. Now that you're binding via the alias to the `highlightColor`, modify the `onMouseEnter()` method to use that property.
If someone neglects to bind to `appHighlightColor`, highlight the host element in red: If someone neglects to bind to `appHighlightColor`, highlight the host element in red:
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" title="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" header="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter"></code-example>
Here's the latest version of the directive class. Here's the latest version of the directive class.
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" title="src/app/highlight.directive.ts (excerpt)"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" header="src/app/highlight.directive.ts (excerpt)"></code-example>
## Write a harness to try it ## Write a harness to try it
@ -259,11 +259,11 @@ lets you pick the highlight color with a radio button and bind your color choice
Update <code>app.component.html</code> as follows: Update <code>app.component.html</code> as follows:
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (v2)" region="v2"></code-example> <code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (v2)" region="v2"></code-example>
Revise the `AppComponent.color` so that it has no initial value. Revise the `AppComponent.color` so that it has no initial value.
<code-example path="attribute-directives/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts (class)" region="class"></code-example> <code-example path="attribute-directives/src/app/app.component.ts" linenums="false" header="src/app/app.component.ts (class)" region="class"></code-example>
Here are the harness and directive in action. Here are the harness and directive in action.
@ -283,12 +283,12 @@ Let the template developer set the default color.
Add a second **input** property to `HighlightDirective` called `defaultColor`: Add a second **input** property to `HighlightDirective` called `defaultColor`:
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (defaultColor)" region="defaultColor"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (defaultColor)" region="defaultColor"></code-example>
Revise the directive's `onMouseEnter` so that it first tries to highlight with the `highlightColor`, Revise the directive's `onMouseEnter` so that it first tries to highlight with the `highlightColor`,
then with the `defaultColor`, and falls back to "red" if both properties are undefined. then with the `defaultColor`, and falls back to "red" if both properties are undefined.
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (mouse-enter)" region="mouse-enter"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (mouse-enter)" region="mouse-enter"></code-example>
How do you bind to a second property when you're already binding to the `appHighlight` attribute name? How do you bind to a second property when you're already binding to the `appHighlight` attribute name?
@ -296,7 +296,7 @@ As with components, you can add as many directive property bindings as you need
The developer should be able to write the following template HTML to both bind to the `AppComponent.color` The developer should be able to write the following template HTML to both bind to the `AppComponent.color`
and fall back to "violet" as the default color. and fall back to "violet" as the default color.
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (defaultColor)" region="defaultColor"></code-example> <code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (defaultColor)" region="defaultColor"></code-example>
Angular knows that the `defaultColor` binding belongs to the `HighlightDirective` Angular knows that the `defaultColor` binding belongs to the `HighlightDirective`
because you made it _public_ with the `@Input` decorator. because you made it _public_ with the `@Input` decorator.
@ -319,12 +319,12 @@ This page covered how to:
The final source code follows: The final source code follows:
<code-tabs> <code-tabs>
<code-pane title="app/app.component.ts" path="attribute-directives/src/app/app.component.ts"></code-pane> <code-pane header="app/app.component.ts" path="attribute-directives/src/app/app.component.ts"></code-pane>
<code-pane title="app/app.component.html" path="attribute-directives/src/app/app.component.html"></code-pane> <code-pane header="app/app.component.html" path="attribute-directives/src/app/app.component.html"></code-pane>
<code-pane title="app/highlight.directive.ts" path="attribute-directives/src/app/highlight.directive.ts"></code-pane> <code-pane header="app/highlight.directive.ts" path="attribute-directives/src/app/highlight.directive.ts"></code-pane>
<code-pane title="app/app.module.ts" path="attribute-directives/src/app/app.module.ts"></code-pane> <code-pane header="app/app.module.ts" path="attribute-directives/src/app/app.module.ts"></code-pane>
<code-pane title="main.ts" path="attribute-directives/src/main.ts"></code-pane> <code-pane header="main.ts" path="attribute-directives/src/main.ts"></code-pane>
<code-pane title="index.html" path="attribute-directives/src/index.html"></code-pane> <code-pane header="index.html" path="attribute-directives/src/index.html"></code-pane>
</code-tabs> </code-tabs>
@ -338,11 +338,11 @@ You can also experience and download the <live-example title="Attribute Directiv
In this demo, the `highlightColor` property is an ***input*** property of In this demo, the `highlightColor` property is an ***input*** property of
the `HighlightDirective`. You've seen it applied without an alias: the `HighlightDirective`. You've seen it applied without an alias:
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (color)" region="color"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
You've seen it with an alias: You've seen it with an alias:
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (color)" region="color"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
Either way, the `@Input` decorator tells Angular that this property is Either way, the `@Input` decorator tells Angular that this property is
_public_ and available for binding by a parent component. _public_ and available for binding by a parent component.
@ -374,7 +374,7 @@ You can tell if `@Input` is needed by the position of the property name in a bin
Now apply that reasoning to the following example: Now apply that reasoning to the following example:
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (color)" region="color"></code-example> <code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
* The `color` property in the expression on the right belongs to the template's component. * The `color` property in the expression on the right belongs to the template's component.
The template and its component trust each other. The template and its component trust each other.

View File

@ -106,18 +106,18 @@ To use a directive, component, or pipe in a module, you must do a few things:
Those three steps look like the following. In the file where you create your directive, export it. Those three steps look like the following. In the file where you create your directive, export it.
The following example, named `ItemDirective` is the default directive structure that the CLI generates in its own file, `item.directive.ts`: The following example, named `ItemDirective` is the default directive structure that the CLI generates in its own file, `item.directive.ts`:
<code-example path="bootstrapping/src/app/item.directive.ts" region="directive" title="src/app/item.directive.ts" linenums="false"> <code-example path="bootstrapping/src/app/item.directive.ts" region="directive" header="src/app/item.directive.ts" linenums="false">
</code-example> </code-example>
The key point here is that you have to export it so you can import it elsewhere. Next, import it The key point here is that you have to export it so you can import it elsewhere. Next, import it
into the NgModule, in this example `app.module.ts`, with a JavaScript import statement: into the NgModule, in this example `app.module.ts`, with a JavaScript import statement:
<code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" title="src/app/app.module.ts" linenums="false"> <code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
And in the same file, add it to the `@NgModule` `declarations` array: And in the same file, add it to the `@NgModule` `declarations` array:
<code-example path="bootstrapping/src/app/app.module.ts" region="declarations" title="src/app/app.module.ts" linenums="false"> <code-example path="bootstrapping/src/app/app.module.ts" region="declarations" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>

View File

@ -140,7 +140,7 @@ For example, [if you need the web animations polyfill](http://caniuse.com/#feat=
Then open the `polyfills.ts` file and un-comment the corresponding `import` statement as in the following example: Then open the `polyfills.ts` file and un-comment the corresponding `import` statement as in the following example:
<code-example title="src/polyfills.ts"> <code-example header="src/polyfills.ts">
/** /**
* Required to support Web Animations `@angular/platform-browser/animations`. * Required to support Web Animations `@angular/platform-browser/animations`.
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
@ -553,7 +553,7 @@ computed with the <a href="http://closure-compiler.appspot.com/home">closure com
If you are not using the CLI, you should add your polyfill scripts directly to the host web page (`index.html`), perhaps like this. If you are not using the CLI, you should add your polyfill scripts directly to the host web page (`index.html`), perhaps like this.
<code-example title="src/index.html"> <code-example header="src/index.html">
&lt;!-- pre-zone polyfills --> &lt;!-- pre-zone polyfills -->
&lt;script src="node_modules/core-js/client/shim.min.js">&lt;/script> &lt;script src="node_modules/core-js/client/shim.min.js">&lt;/script>
&lt;script src="node_modules/web-animations-js/web-animations.min.js">&lt;/script> &lt;script src="node_modules/web-animations-js/web-animations.min.js">&lt;/script>

View File

@ -38,7 +38,7 @@ The following example demonstrates how to use `query()` and `stagger()` function
* Animate each element on screen for 0.5 seconds using a custom-defined easing curve, simultaneously fading it in and un-transforming it. * Animate each element on screen for 0.5 seconds using a custom-defined easing curve, simultaneously fading it in and un-transforming it.
<code-example path="animations/src/app/hero-list-page.component.ts" title="src/app/hero-list-page.component.ts" region="page-animations" language="typescript" linenums="false"></code-example> <code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="page-animations" language="typescript" linenums="false"></code-example>
## Parallel animation using group() function ## Parallel animation using group() function
@ -51,7 +51,7 @@ You've seen how to add a delay between each successive animation. But you may al
In the following example, using groups on both `:enter` and `:leave` allow for two different timing configurations. They're applied to the same element in parallel, but run independently. In the following example, using groups on both `:enter` and `:leave` allow for two different timing configurations. They're applied to the same element in parallel, but run independently.
<code-example path="animations/src/app/hero-list-groups.component.ts" region="animationdef" title="src/app/hero-list-groups.component.ts (excerpt)" language="typescript" linenums="false"></code-example> <code-example path="animations/src/app/hero-list-groups.component.ts" region="animationdef" header="src/app/hero-list-groups.component.ts (excerpt)" language="typescript" linenums="false"></code-example>
## Sequential vs. parallel animations ## Sequential vs. parallel animations
@ -70,11 +70,11 @@ The filter works in real time as you type. Elements leave the page as you type e
The HTML template contains a trigger called `filterAnimation`. The HTML template contains a trigger called `filterAnimation`.
<code-example path="animations/src/app/hero-list-page.component.html" title="src/app/hero-list-page.component.html" region="filter-animations"></code-example> <code-example path="animations/src/app/hero-list-page.component.html" header="src/app/hero-list-page.component.html" region="filter-animations"></code-example>
The component file contains three transitions. The component file contains three transitions.
<code-example path="animations/src/app/hero-list-page.component.ts" title="src/app/hero-list-page.component.ts" region="filter-animations" language="typescript" linenums="false"></code-example> <code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="filter-animations" language="typescript" linenums="false"></code-example>
The animation does the following: The animation does the following:

View File

@ -28,7 +28,7 @@ in which two or more components share information.
typically adorned with [@Input decorations](guide/template-syntax#inputs-outputs). typically adorned with [@Input decorations](guide/template-syntax#inputs-outputs).
<code-example path="component-interaction/src/app/hero-child.component.ts" title="component-interaction/src/app/hero-child.component.ts"> <code-example path="component-interaction/src/app/hero-child.component.ts" header="component-interaction/src/app/hero-child.component.ts">
</code-example> </code-example>
@ -41,7 +41,7 @@ binding its `master` string property to the child's `master` alias,
and each iteration's `hero` instance to the child's `hero` property. and each iteration's `hero` instance to the child's `hero` property.
<code-example path="component-interaction/src/app/hero-parent.component.ts" title="component-interaction/src/app/hero-parent.component.ts"> <code-example path="component-interaction/src/app/hero-parent.component.ts" header="component-interaction/src/app/hero-parent.component.ts">
</code-example> </code-example>
@ -61,7 +61,7 @@ The running application displays three heroes:
E2E test that all children were instantiated and displayed as expected: E2E test that all children were instantiated and displayed as expected:
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child" title="component-interaction/e2e/src/app.e2e-spec.ts"> <code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child" header="component-interaction/e2e/src/app.e2e-spec.ts">
</code-example> </code-example>
@ -79,7 +79,7 @@ The setter of the `name` input property in the child `NameChildComponent`
trims the whitespace from a name and replaces an empty value with default text. trims the whitespace from a name and replaces an empty value with default text.
<code-example path="component-interaction/src/app/name-child.component.ts" title="component-interaction/src/app/name-child.component.ts"> <code-example path="component-interaction/src/app/name-child.component.ts" header="component-interaction/src/app/name-child.component.ts">
</code-example> </code-example>
@ -88,7 +88,7 @@ trims the whitespace from a name and replaces an empty value with default text.
Here's the `NameParentComponent` demonstrating name variations including a name with all spaces: Here's the `NameParentComponent` demonstrating name variations including a name with all spaces:
<code-example path="component-interaction/src/app/name-parent.component.ts" title="component-interaction/src/app/name-parent.component.ts"> <code-example path="component-interaction/src/app/name-parent.component.ts" header="component-interaction/src/app/name-parent.component.ts">
</code-example> </code-example>
@ -105,7 +105,7 @@ Here's the `NameParentComponent` demonstrating name variations including a name
E2E tests of input property setter with empty and non-empty names: E2E tests of input property setter with empty and non-empty names:
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child-setter" title="component-interaction/e2e/src/app.e2e-spec.ts"> <code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child-setter" header="component-interaction/e2e/src/app.e2e-spec.ts">
</code-example> </code-example>
@ -134,7 +134,7 @@ Learn about `ngOnChanges()` in the [LifeCycle Hooks](guide/lifecycle-hooks) chap
This `VersionChildComponent` detects changes to the `major` and `minor` input properties and composes a log message reporting these changes: This `VersionChildComponent` detects changes to the `major` and `minor` input properties and composes a log message reporting these changes:
<code-example path="component-interaction/src/app/version-child.component.ts" title="component-interaction/src/app/version-child.component.ts"> <code-example path="component-interaction/src/app/version-child.component.ts" header="component-interaction/src/app/version-child.component.ts">
</code-example> </code-example>
@ -143,7 +143,7 @@ This `VersionChildComponent` detects changes to the `major` and `minor` input pr
The `VersionParentComponent` supplies the `minor` and `major` values and binds buttons to methods that change them. The `VersionParentComponent` supplies the `minor` and `major` values and binds buttons to methods that change them.
<code-example path="component-interaction/src/app/version-parent.component.ts" title="component-interaction/src/app/version-parent.component.ts"> <code-example path="component-interaction/src/app/version-parent.component.ts" header="component-interaction/src/app/version-parent.component.ts">
</code-example> </code-example>
@ -164,7 +164,7 @@ Test that ***both*** input properties are set initially and that button clicks t
the expected `ngOnChanges` calls and values: the expected `ngOnChanges` calls and values:
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child-onchanges" title="component-interaction/e2e/src/app.e2e-spec.ts"> <code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child-onchanges" header="component-interaction/e2e/src/app.e2e-spec.ts">
</code-example> </code-example>
@ -184,7 +184,7 @@ The child's `EventEmitter` property is an ***output property***,
as seen in this `VoterComponent`: as seen in this `VoterComponent`:
<code-example path="component-interaction/src/app/voter.component.ts" title="component-interaction/src/app/voter.component.ts"> <code-example path="component-interaction/src/app/voter.component.ts" header="component-interaction/src/app/voter.component.ts">
</code-example> </code-example>
@ -196,7 +196,7 @@ The parent `VoteTakerComponent` binds an event handler called `onVoted()` that r
payload `$event` and updates a counter. payload `$event` and updates a counter.
<code-example path="component-interaction/src/app/votetaker.component.ts" title="component-interaction/src/app/votetaker.component.ts"> <code-example path="component-interaction/src/app/votetaker.component.ts" header="component-interaction/src/app/votetaker.component.ts">
</code-example> </code-example>
@ -217,7 +217,7 @@ and the method processes it:
Test that clicking the *Agree* and *Disagree* buttons update the appropriate counters: Test that clicking the *Agree* and *Disagree* buttons update the appropriate counters:
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="child-to-parent" title="component-interaction/e2e/src/app.e2e-spec.ts"> <code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="child-to-parent" header="component-interaction/e2e/src/app.e2e-spec.ts">
</code-example> </code-example>
@ -240,7 +240,7 @@ The following is a child `CountdownTimerComponent` that repeatedly counts down t
It has `start` and `stop` methods that control the clock and it displays a It has `start` and `stop` methods that control the clock and it displays a
countdown status message in its own template. countdown status message in its own template.
<code-example path="component-interaction/src/app/countdown-timer.component.ts" title="component-interaction/src/app/countdown-timer.component.ts"> <code-example path="component-interaction/src/app/countdown-timer.component.ts" header="component-interaction/src/app/countdown-timer.component.ts">
</code-example> </code-example>
@ -249,7 +249,7 @@ countdown status message in its own template.
The `CountdownLocalVarParentComponent` that hosts the timer component is as follows: The `CountdownLocalVarParentComponent` that hosts the timer component is as follows:
<code-example path="component-interaction/src/app/countdown-parent.component.ts" region="lv" title="component-interaction/src/app/countdown-parent.component.ts"> <code-example path="component-interaction/src/app/countdown-parent.component.ts" region="lv" header="component-interaction/src/app/countdown-parent.component.ts">
</code-example> </code-example>
@ -284,7 +284,7 @@ match the seconds displayed in the child's status message.
Test also that clicking the *Stop* button pauses the countdown timer: Test also that clicking the *Stop* button pauses the countdown timer:
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="countdown-timer-tests" title="component-interaction/e2e/src/app.e2e-spec.ts"> <code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="countdown-timer-tests" header="component-interaction/e2e/src/app.e2e-spec.ts">
</code-example> </code-example>
@ -324,7 +324,7 @@ is solely for the purpose of demonstration.
Here is the parent, `CountdownViewChildParentComponent`: Here is the parent, `CountdownViewChildParentComponent`:
<code-example path="component-interaction/src/app/countdown-parent.component.ts" region="vc" title="component-interaction/src/app/countdown-parent.component.ts"> <code-example path="component-interaction/src/app/countdown-parent.component.ts" region="vc" header="component-interaction/src/app/countdown-parent.component.ts">
</code-example> </code-example>
@ -374,7 +374,7 @@ Components outside this component subtree have no access to the service or their
This `MissionService` connects the `MissionControlComponent` to multiple `AstronautComponent` children. This `MissionService` connects the `MissionControlComponent` to multiple `AstronautComponent` children.
<code-example path="component-interaction/src/app/mission.service.ts" title="component-interaction/src/app/mission.service.ts"> <code-example path="component-interaction/src/app/mission.service.ts" header="component-interaction/src/app/mission.service.ts">
</code-example> </code-example>
@ -384,7 +384,7 @@ The `MissionControlComponent` both provides the instance of the service that it
(through the `providers` metadata array) and injects that instance into itself through its constructor: (through the `providers` metadata array) and injects that instance into itself through its constructor:
<code-example path="component-interaction/src/app/missioncontrol.component.ts" title="component-interaction/src/app/missioncontrol.component.ts"> <code-example path="component-interaction/src/app/missioncontrol.component.ts" header="component-interaction/src/app/missioncontrol.component.ts">
</code-example> </code-example>
@ -394,7 +394,7 @@ The `AstronautComponent` also injects the service in its constructor.
Each `AstronautComponent` is a child of the `MissionControlComponent` and therefore receives its parent's service instance: Each `AstronautComponent` is a child of the `MissionControlComponent` and therefore receives its parent's service instance:
<code-example path="component-interaction/src/app/astronaut.component.ts" title="component-interaction/src/app/astronaut.component.ts"> <code-example path="component-interaction/src/app/astronaut.component.ts" header="component-interaction/src/app/astronaut.component.ts">
</code-example> </code-example>
@ -433,7 +433,7 @@ Tests click buttons of both the parent `MissionControlComponent` and the `Astron
and verify that the history meets expectations: and verify that the history meets expectations:
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="bidirectional-service" title="component-interaction/e2e/src/app.e2e-spec.ts"> <code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="bidirectional-service" header="component-interaction/e2e/src/app.e2e-spec.ts">
</code-example> </code-example>

View File

@ -21,7 +21,7 @@ One way to do this is to set the `styles` property in the component metadata.
The `styles` property takes an array of strings that contain CSS code. The `styles` property takes an array of strings that contain CSS code.
Usually you give it one string, as in the following example: Usually you give it one string, as in the following example:
<code-example path="component-styles/src/app/hero-app.component.ts" title="src/app/hero-app.component.ts" linenums="false"> <code-example path="component-styles/src/app/hero-app.component.ts" header="src/app/hero-app.component.ts" linenums="false">
</code-example> </code-example>
## Style scope ## Style scope
@ -71,7 +71,7 @@ Use the `:host` pseudo-class selector to target styles in the element that *host
targeting elements *inside* the component's template). targeting elements *inside* the component's template).
<code-example path="component-styles/src/app/hero-details.component.css" region="host" title="src/app/hero-details.component.css" linenums="false"> <code-example path="component-styles/src/app/hero-details.component.css" region="host" header="src/app/hero-details.component.css" linenums="false">
</code-example> </code-example>
The `:host` selector is the only way to target the host element. You can't reach The `:host` selector is the only way to target the host element. You can't reach
@ -83,7 +83,7 @@ including another selector inside parentheses after `:host`.
The next example targets the host element again, but only when it also has the `active` CSS class. The next example targets the host element again, but only when it also has the `active` CSS class.
<code-example path="component-styles/src/app/hero-details.component.css" region="hostfunction" title="src/app/hero-details.component.css" linenums="false"> <code-example path="component-styles/src/app/hero-details.component.css" region="hostfunction" header="src/app/hero-details.component.css" linenums="false">
</code-example> </code-example>
### :host-context ### :host-context
@ -99,7 +99,7 @@ up to the document root. The `:host-context()` selector is useful when combined
The following example applies a `background-color` style to all `<h2>` elements *inside* the component, only The following example applies a `background-color` style to all `<h2>` elements *inside* the component, only
if some ancestor element has the CSS class `theme-light`. if some ancestor element has the CSS class `theme-light`.
<code-example path="component-styles/src/app/hero-details.component.css" region="hostcontext" title="src/app/hero-details.component.css" linenums="false"> <code-example path="component-styles/src/app/hero-details.component.css" region="hostcontext" header="src/app/hero-details.component.css" linenums="false">
</code-example> </code-example>
### (deprecated) `/deep/`, `>>>`, and `::ng-deep` ### (deprecated) `/deep/`, `>>>`, and `::ng-deep`
@ -114,7 +114,7 @@ children and content children of the component.
The following example targets all `<h3>` elements, from the host element down The following example targets all `<h3>` elements, from the host element down
through this component to all of its child elements in the DOM. through this component to all of its child elements in the DOM.
<code-example path="component-styles/src/app/hero-details.component.css" region="deep" title="src/app/hero-details.component.css" linenums="false"> <code-example path="component-styles/src/app/hero-details.component.css" region="deep" header="src/app/hero-details.component.css" linenums="false">
</code-example> </code-example>
@ -154,7 +154,7 @@ You can add a `styles` array property to the `@Component` decorator.
Each string in the array defines some CSS for this component. Each string in the array defines some CSS for this component.
<code-example path="component-styles/src/app/hero-app.component.ts" title="src/app/hero-app.component.ts (CSS inline)"> <code-example path="component-styles/src/app/hero-app.component.ts" header="src/app/hero-app.component.ts (CSS inline)">
</code-example> </code-example>
<div class="alert is-critical"> <div class="alert is-critical">
@ -176,8 +176,8 @@ You can load styles from external CSS files by adding a `styleUrls` property
to a component's `@Component` decorator: to a component's `@Component` decorator:
<code-tabs> <code-tabs>
<code-pane title="src/app/hero-app.component.ts (CSS in file)" path="component-styles/src/app/hero-app.component.1.ts"></code-pane> <code-pane header="src/app/hero-app.component.ts (CSS in file)" path="component-styles/src/app/hero-app.component.1.ts"></code-pane>
<code-pane title="src/app/hero-app.component.css" path="component-styles/src/app/hero-app.component.css"></code-pane> <code-pane header="src/app/hero-app.component.css" path="component-styles/src/app/hero-app.component.css"></code-pane>
</code-tabs> </code-tabs>
<div class="alert is-critical"> <div class="alert is-critical">
@ -204,14 +204,14 @@ ng generate component hero-app
You can embed CSS styles directly into the HTML template by putting them You can embed CSS styles directly into the HTML template by putting them
inside `<style>` tags. inside `<style>` tags.
<code-example path="component-styles/src/app/hero-controls.component.ts" region="inlinestyles" title="src/app/hero-controls.component.ts"> <code-example path="component-styles/src/app/hero-controls.component.ts" region="inlinestyles" header="src/app/hero-controls.component.ts">
</code-example> </code-example>
### Template link tags ### Template link tags
You can also write `<link>` tags into the component's HTML template. You can also write `<link>` tags into the component's HTML template.
<code-example path="component-styles/src/app/hero-team.component.ts" region="stylelink" title="src/app/hero-team.component.ts"> <code-example path="component-styles/src/app/hero-team.component.ts" region="stylelink" header="src/app/hero-team.component.ts">
</code-example> </code-example>
<div class="alert is-critical"> <div class="alert is-critical">
@ -230,7 +230,7 @@ on the [MDN](https://developer.mozilla.org) site.
In this case, the URL is relative to the CSS file into which you're importing. In this case, the URL is relative to the CSS file into which you're importing.
<code-example path="component-styles/src/app/hero-details.component.css" region="import" title="src/app/hero-details.component.css (excerpt)"> <code-example path="component-styles/src/app/hero-details.component.css" region="import" header="src/app/hero-details.component.css (excerpt)">
</code-example> </code-example>
### External and global style files ### External and global style files
@ -298,7 +298,7 @@ Choose from the following modes:
To set the components encapsulation mode, use the `encapsulation` property in the component metadata: To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" title="src/app/quest-summary.component.ts" linenums="false"> <code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts" linenums="false">
</code-example> </code-example>
`ShadowDom` view encapsulation only works on browsers that have native support `ShadowDom` view encapsulation only works on browsers that have native support

View File

@ -21,7 +21,7 @@ constructor, and lets the framework provide them.
The following example shows that `AppComponent` declares its dependence on `LoggerService` and `UserContext`. The following example shows that `AppComponent` declares its dependence on `LoggerService` and `UserContext`.
<code-example path="dependency-injection-in-action/src/app/app.component.ts" region="ctor" title="src/app/app.component.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/app.component.ts" region="ctor" header="src/app/app.component.ts" linenums="false">
</code-example> </code-example>
@ -30,7 +30,7 @@ The following example shows that `AppComponent` declares its dependence on `Logg
`UserService`, another service that gathers information about a particular user. `UserService`, another service that gathers information about a particular user.
<code-example path="dependency-injection-in-action/src/app/user-context.service.ts" region="injectables" title="user-context.service.ts (injection)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/user-context.service.ts" region="injectables" header="user-context.service.ts (injection)" linenums="false">
</code-example> </code-example>
@ -68,7 +68,7 @@ by providing that service *at the sub-root component for that branch*.
This example shows how to make a different instance of `HeroService` available to `HeroesBaseComponent` This example shows how to make a different instance of `HeroService` available to `HeroesBaseComponent`
by adding it to the `providers` array of the `@Component()` decorator of the sub-component. by adding it to the `providers` array of the `@Component()` decorator of the sub-component.
<code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="injection" title="src/app/sorted-heroes.component.ts (HeroesBaseComponent excerpt)"> <code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="injection" header="src/app/sorted-heroes.component.ts (HeroesBaseComponent excerpt)">
</code-example> </code-example>
@ -103,7 +103,7 @@ This is called *sandboxing* because each service and component instance has its
In this example, `HeroBiosComponent` presents three instances of `HeroBioComponent`. In this example, `HeroBiosComponent` presents three instances of `HeroBioComponent`.
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="simple" title="ap/hero-bios.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="simple" header="ap/hero-bios.component.ts">
</code-example> </code-example>
@ -111,7 +111,7 @@ In this example, `HeroBiosComponent` presents three instances of `HeroBioCompone
Each `HeroBioComponent` can edit a single hero's biography. Each `HeroBioComponent` can edit a single hero's biography.
`HeroBioComponent` relies on `HeroCacheService` to fetch, cache, and perform other persistence operations on that hero. `HeroBioComponent` relies on `HeroCacheService` to fetch, cache, and perform other persistence operations on that hero.
<code-example path="dependency-injection-in-action/src/app/hero-cache.service.ts" region="service" title="src/app/hero-cache.service.ts"> <code-example path="dependency-injection-in-action/src/app/hero-cache.service.ts" region="service" header="src/app/hero-cache.service.ts">
</code-example> </code-example>
@ -122,7 +122,7 @@ as they'd be competing with each other to determine which hero to cache.
Instead, each `HeroBioComponent` gets its *own* `HeroCacheService` instance Instead, each `HeroBioComponent` gets its *own* `HeroCacheService` instance
by listing `HeroCacheService` in its metadata `providers` array. by listing `HeroCacheService` in its metadata `providers` array.
<code-example path="dependency-injection-in-action/src/app/hero-bio.component.ts" region="component" title="src/app/hero-bio.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-bio.component.ts" region="component" header="src/app/hero-bio.component.ts">
</code-example> </code-example>
@ -179,13 +179,13 @@ that parent component becomes the host. The following example covers this second
These decorators can be used individually or together, as shown in the example. These decorators can be used individually or together, as shown in the example.
This `HeroBiosAndContactsComponent` is a revision of `HeroBiosComponent` which you looked at [above](guide/dependency-injection-in-action#hero-bios-component). This `HeroBiosAndContactsComponent` is a revision of `HeroBiosComponent` which you looked at [above](guide/dependency-injection-in-action#hero-bios-component).
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="hero-bios-and-contacts" title="src/app/hero-bios.component.ts (HeroBiosAndContactsComponent)"> <code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="hero-bios-and-contacts" header="src/app/hero-bios.component.ts (HeroBiosAndContactsComponent)">
</code-example> </code-example>
Focus on the template: Focus on the template:
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="template" title="dependency-injection-in-action/src/app/hero-bios.component.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="template" header="dependency-injection-in-action/src/app/hero-bios.component.ts" linenums="false">
</code-example> </code-example>
@ -193,7 +193,7 @@ Now there's a new `<hero-contact>` element between the `<hero-bio>` tags.
Angular *projects*, or *transcludes*, the corresponding `HeroContactComponent` into the `HeroBioComponent` view, Angular *projects*, or *transcludes*, the corresponding `HeroContactComponent` into the `HeroBioComponent` view,
placing it in the `<ng-content>` slot of the `HeroBioComponent` template. placing it in the `<ng-content>` slot of the `HeroBioComponent` template.
<code-example path="dependency-injection-in-action/src/app/hero-bio.component.ts" region="template" title="src/app/hero-bio.component.ts (template)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/hero-bio.component.ts" region="template" header="src/app/hero-bio.component.ts (template)" linenums="false">
</code-example> </code-example>
@ -206,13 +206,13 @@ The result is shown below, with the hero's telephone number from `HeroContactCom
Here's `HeroContactComponent`, which demonstrates the qualifying decorators. Here's `HeroContactComponent`, which demonstrates the qualifying decorators.
<code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="component" title="src/app/hero-contact.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="component" header="src/app/hero-contact.component.ts">
</code-example> </code-example>
Focus on the constructor parameters. Focus on the constructor parameters.
<code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="ctor-params" title="src/app/hero-contact.component.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="ctor-params" header="src/app/hero-contact.component.ts" linenums="false">
</code-example> </code-example>
@ -256,7 +256,7 @@ the app throws an exception when it cannot find the required logger at the host
Using a custom provider allows you to provide a concrete implementation for implicit dependencies, such as built-in browser APIs. The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`. Using a custom provider allows you to provide a concrete implementation for implicit dependencies, such as built-in browser APIs. The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`.
<code-example path="dependency-injection-in-action/src/app/storage.service.ts" title="src/app/storage.service.ts"> <code-example path="dependency-injection-in-action/src/app/storage.service.ts" header="src/app/storage.service.ts">
</code-example> </code-example>
@ -266,7 +266,7 @@ The `factory` function returns the `localStorage` property that is attached to t
Providers can also be scoped by injector through constructor parameter decorators. The following example overrides the `BROWSER_STORAGE` token in the `Component` class `providers` with the `sessionStorage` browser API. The same `BrowserStorageService` is injected twice in the constructor, decorated with `@Self` and `@SkipSelf` to define which injector handles the provider dependency. Providers can also be scoped by injector through constructor parameter decorators. The following example overrides the `BROWSER_STORAGE` token in the `Component` class `providers` with the `sessionStorage` browser API. The same `BrowserStorageService` is injected twice in the constructor, decorated with `@Self` and `@SkipSelf` to define which injector handles the provider dependency.
<code-example path="dependency-injection-in-action/src/app/storage.component.ts" title="src/app/storage.component.ts"> <code-example path="dependency-injection-in-action/src/app/storage.component.ts" header="src/app/storage.component.ts">
</code-example> </code-example>
@ -283,7 +283,7 @@ As a result, you might need to access a component's DOM element.
To illustrate, here's a simplified version of `HighlightDirective` from To illustrate, here's a simplified version of `HighlightDirective` from
the [Attribute Directives](guide/attribute-directives) page. the [Attribute Directives](guide/attribute-directives) page.
<code-example path="dependency-injection-in-action/src/app/highlight.directive.ts" title="src/app/highlight.directive.ts"> <code-example path="dependency-injection-in-action/src/app/highlight.directive.ts" header="src/app/highlight.directive.ts">
</code-example> </code-example>
@ -297,7 +297,7 @@ whose `nativeElement` property exposes the DOM element for the directive to mani
The sample code applies the directive's `myHighlight` attribute to two `<div>` tags, The sample code applies the directive's `myHighlight` attribute to two `<div>` tags,
first without a value (yielding the default color) and then with an assigned color value. first without a value (yielding the default color) and then with an assigned color value.
<code-example path="dependency-injection-in-action/src/app/app.component.html" region="highlight" title="src/app/app.component.html (highlight)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/app.component.html" region="highlight" header="src/app/app.component.html (highlight)" linenums="false">
</code-example> </code-example>
@ -323,7 +323,7 @@ Angular passes this token to the injector and assigns the result to the paramete
The following is a typical example. The following is a typical example.
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="ctor" title="src/app/hero-bios.component.ts (component constructor injection)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="ctor" header="src/app/hero-bios.component.ts (component constructor injection)" linenums="false">
</code-example> </code-example>
@ -366,7 +366,7 @@ It's visually simple: a few properties and the logs produced by a logger.
The code behind it customizes how and where the DI framework provides dependencies. The code behind it customizes how and where the DI framework provides dependencies.
The use cases illustrate different ways to use the [*provide* object literal](guide/dependency-injection-providers#provide) to associate a definition object with a DI token. The use cases illustrate different ways to use the [*provide* object literal](guide/dependency-injection-providers#provide) to associate a definition object with a DI token.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="hero-of-the-month" title="hero-of-the-month.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="hero-of-the-month" header="hero-of-the-month.component.ts">
</code-example> </code-example>
@ -384,7 +384,7 @@ You can also use a value provider in a unit test to provide mock data in place o
The `HeroOfTheMonthComponent` example has two value providers. The `HeroOfTheMonthComponent` example has two value providers.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-value" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-value" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
</code-example> </code-example>
@ -405,7 +405,7 @@ The title string literal is immediately available.
The `someHero` variable in this example was set earlier in the file as shown below. The `someHero` variable in this example was set earlier in the file as shown below.
You can't use a variable whose value will be defined later. You can't use a variable whose value will be defined later.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="some-hero" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="some-hero" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts">
</code-example> </code-example>
@ -425,7 +425,7 @@ extend the default class, or emulate the behavior of the real class in a test ca
The following code shows two examples in `HeroOfTheMonthComponent`. The following code shows two examples in `HeroOfTheMonthComponent`.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-class" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-class" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
</code-example> </code-example>
@ -446,7 +446,7 @@ Components outside the tree continue to receive the original `LoggerService` ins
`DateLoggerService` inherits from `LoggerService`; it appends the current date/time to each message: `DateLoggerService` inherits from `LoggerService`; it appends the current date/time to each message:
<code-example path="dependency-injection-in-action/src/app/date-logger.service.ts" region="date-logger-service" title="src/app/date-logger.service.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/date-logger.service.ts" region="date-logger-service" header="src/app/date-logger.service.ts" linenums="false">
</code-example> </code-example>
@ -458,7 +458,7 @@ The `useExisting` provider key lets you map one token to another.
In effect, the first token is an *alias* for the service associated with the second token, In effect, the first token is an *alias* for the service associated with the second token,
creating two ways to access the same service object. creating two ways to access the same service object.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-existing" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-existing" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts">
</code-example> </code-example>
@ -470,13 +470,13 @@ You might want to shrink that API surface to just the members you actually need.
In this example, the `MinimalLogger` [class-interface](#class-interface) reduces the API to two members: In this example, the `MinimalLogger` [class-interface](#class-interface) reduces the API to two members:
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" title="src/app/minimal-logger.service.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="src/app/minimal-logger.service.ts" linenums="false">
</code-example> </code-example>
The following example puts `MinimalLogger` to use in a simplified version of `HeroOfTheMonthComponent`. The following example puts `MinimalLogger` to use in a simplified version of `HeroOfTheMonthComponent`.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.1.ts" title="src/app/hero-of-the-month.component.ts (minimal version)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.1.ts" header="src/app/hero-of-the-month.component.ts (minimal version)" linenums="false">
</code-example> </code-example>
@ -507,7 +507,7 @@ This is illustrated in the following image, which displays the logging date.
The `useFactory` provider key lets you create a dependency object by calling a factory function, The `useFactory` provider key lets you create a dependency object by calling a factory function,
as in the following example. as in the following example.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-factory" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-factory" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts">
</code-example> </code-example>
@ -530,7 +530,7 @@ The `runnersUpFactory()` returns the *provider factory function*, which can use
the passed-in state value and the injected services `Hero` and `HeroService`. the passed-in state value and the injected services `Hero` and `HeroService`.
<code-example path="dependency-injection-in-action/src/app/runners-up.ts" region="factory-synopsis" title="runners-up.ts (excerpt)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/runners-up.ts" region="factory-synopsis" header="runners-up.ts (excerpt)" linenums="false">
</code-example> </code-example>
@ -570,13 +570,13 @@ That's the subject of the next section.
The previous *Hero of the Month* example used the `MinimalLogger` class The previous *Hero of the Month* example used the `MinimalLogger` class
as the token for a provider of `LoggerService`. as the token for a provider of `LoggerService`.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-existing" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-existing" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts">
</code-example> </code-example>
`MinimalLogger` is an abstract class. `MinimalLogger` is an abstract class.
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" title="dependency-injection-in-action/src/app/minimal-logger.service.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="dependency-injection-in-action/src/app/minimal-logger.service.ts" linenums="false">
</code-example> </code-example>
@ -604,7 +604,7 @@ Using a class as an interface gives you the characteristics of an interface in a
To minimize memory cost, however, the class should have *no implementation*. To minimize memory cost, however, the class should have *no implementation*.
The `MinimalLogger` transpiles to this unoptimized, pre-minified JavaScript for a constructor function. The `MinimalLogger` transpiles to this unoptimized, pre-minified JavaScript for a constructor function.
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" region="minimal-logger-transpiled" title="dependency-injection-in-action/src/app/minimal-logger.service.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" region="minimal-logger-transpiled" header="dependency-injection-in-action/src/app/minimal-logger.service.ts" linenums="false">
</code-example> </code-example>
@ -633,13 +633,13 @@ another token that happens to have the same name.
You encountered them twice in the *Hero of the Month* example, You encountered them twice in the *Hero of the Month* example,
in the *title* value provider and in the *runnersUp* factory provider. in the *title* value provider and in the *runnersUp* factory provider.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="provide-injection-token" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="provide-injection-token" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
</code-example> </code-example>
You created the `TITLE` token like this: You created the `TITLE` token like this:
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="injection-token" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="injection-token" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
</code-example> </code-example>
@ -667,7 +667,7 @@ The `HeroesBaseComponent` can stand on its own.
It demands its own instance of `HeroService` to get heroes It demands its own instance of `HeroService` to get heroes
and displays them in the order they arrive from the database. and displays them in the order they arrive from the database.
<code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="heroes-base" title="src/app/sorted-heroes.component.ts (HeroesBaseComponent)"> <code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="heroes-base" header="src/app/sorted-heroes.component.ts (HeroesBaseComponent)">
</code-example> </code-example>
@ -693,7 +693,7 @@ You must provide the `HeroService` again for *this* component,
then pass it down to the base class inside the constructor. then pass it down to the base class inside the constructor.
<code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="sorted-heroes" title="src/app/sorted-heroes.component.ts (SortedHeroesComponent)"> <code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="sorted-heroes" header="src/app/sorted-heroes.component.ts (SortedHeroesComponent)">
</code-example> </code-example>
@ -731,7 +731,7 @@ appear *above* the class definition.
Break the circularity with `forwardRef`. Break the circularity with `forwardRef`.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" title="parent-finder.component.ts (AlexComponent providers)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="parent-finder.component.ts (AlexComponent providers)" linenums="false">
</code-example> </code-example>

View File

@ -40,7 +40,7 @@ In the following example, the parent `AlexComponent` has several children includ
{@a alex} {@a alex}
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-1" title="parent-finder.component.ts (AlexComponent v.1)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-1" header="parent-finder.component.ts (AlexComponent v.1)" linenums="false">
</code-example> </code-example>
@ -49,7 +49,7 @@ In the following example, the parent `AlexComponent` has several children includ
*Cathy* reports whether or not she has access to *Alex* *Cathy* reports whether or not she has access to *Alex*
after injecting an `AlexComponent` into her constructor: after injecting an `AlexComponent` into her constructor:
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="cathy" title="parent-finder.component.ts (CathyComponent)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="cathy" header="parent-finder.component.ts (CathyComponent)" linenums="false">
</code-example> </code-example>
@ -98,7 +98,7 @@ inject its parent via the parent's base class*.
The sample's `CraigComponent` explores this question. [Looking back](#alex), The sample's `CraigComponent` explores this question. [Looking back](#alex),
you see that the `Alex` component *extends* (*inherits*) from a class named `Base`. you see that the `Alex` component *extends* (*inherits*) from a class named `Base`.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" title="parent-finder.component.ts (Alex class signature)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" header="parent-finder.component.ts (Alex class signature)" linenums="false">
</code-example> </code-example>
@ -106,7 +106,7 @@ you see that the `Alex` component *extends* (*inherits*) from a class named `Bas
The `CraigComponent` tries to inject `Base` into its `alex` constructor parameter and reports if it succeeded. The `CraigComponent` tries to inject `Base` into its `alex` constructor parameter and reports if it succeeded.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="craig" title="parent-finder.component.ts (CraigComponent)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="craig" header="parent-finder.component.ts (CraigComponent)" linenums="false">
</code-example> </code-example>
@ -138,7 +138,7 @@ and add that provider to the `providers` array of the `@Component()` metadata fo
{@a alex-providers} {@a alex-providers}
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" title="parent-finder.component.ts (AlexComponent providers)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="parent-finder.component.ts (AlexComponent providers)" linenums="false">
</code-example> </code-example>
@ -149,7 +149,7 @@ The [*forwardRef*](guide/dependency-injection-in-action#forwardref) breaks the c
*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" header="parent-finder.component.ts (CarolComponent class)" linenums="false">
</code-example> </code-example>
@ -177,7 +177,7 @@ That means he must both *inject* the `Parent` class interface to get *Alice* and
Here's *Barry*. Here's *Barry*.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="barry" title="parent-finder.component.ts (BarryComponent)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="barry" header="parent-finder.component.ts (BarryComponent)" linenums="false">
</code-example> </code-example>
@ -190,11 +190,11 @@ For now, focus on *Barry*'s constructor.
<code-tabs> <code-tabs>
<code-pane title="Barry's constructor" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="barry-ctor"> <code-pane header="Barry's constructor" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="barry-ctor">
</code-pane> </code-pane>
<code-pane title="Carol's constructor" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="carol-ctor"> <code-pane header="Carol's constructor" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="carol-ctor">
</code-pane> </code-pane>
@ -229,7 +229,7 @@ You [learned earlier](guide/dependency-injection-in-action#class-interface) that
The example defines a `Parent` class interface. The example defines a `Parent` class interface.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="parent" title="parent-finder.component.ts (Parent class-interface)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="parent" header="parent-finder.component.ts (Parent class-interface)" linenums="false">
</code-example> </code-example>
@ -241,7 +241,7 @@ Such a narrow interface helps decouple the child component class from its parent
A component that could serve as a parent *should* implement the class interface as the `AliceComponent` does. A component that could serve as a parent *should* implement the class interface as the `AliceComponent` does.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-class-signature" title="parent-finder.component.ts (AliceComponent class signature)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-class-signature" header="parent-finder.component.ts (AliceComponent class signature)" linenums="false">
</code-example> </code-example>
@ -251,7 +251,7 @@ Doing so adds clarity to the code. But it's not technically necessary.
Although `AlexComponent` has a `name` property, as required by its `Base` class, Although `AlexComponent` has a `name` property, as required by its `Base` class,
its class signature doesn't mention `Parent`. its class signature doesn't mention `Parent`.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" title="parent-finder.component.ts (AlexComponent class signature)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" header="parent-finder.component.ts (AlexComponent class signature)" linenums="false">
</code-example> </code-example>
@ -277,19 +277,19 @@ It doesn't in this example *only* to demonstrate that the code will compile and
Writing variations of the same parent *alias provider* gets old quickly, Writing variations of the same parent *alias provider* gets old quickly,
especially this awful mouthful with a [*forwardRef*](guide/dependency-injection-in-action#forwardref). especially this awful mouthful with a [*forwardRef*](guide/dependency-injection-in-action#forwardref).
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" title="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
</code-example> </code-example>
You can extract that logic into a helper function like the following. You can extract that logic into a helper function like the following.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-the-parent" title="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-the-parent" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
</code-example> </code-example>
Now you can add a simpler, more meaningful parent provider to your components. Now you can add a simpler, more meaningful parent provider to your components.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-providers" title="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
</code-example> </code-example>
@ -299,14 +299,14 @@ The application might have a variety of parent types, each with its own class in
Here's a revised version that defaults to `parent` but also accepts an optional second parameter for a different parent class interface. Here's a revised version that defaults to `parent` but also accepts an optional second parameter for a different parent class interface.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-parent" title="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-parent" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
</code-example> </code-example>
And here's how you could use it with a different parent type. And here's how you could use it with a different parent type.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="beth-providers" title="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false"> <code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="beth-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
</code-example> </code-example>

View File

@ -130,7 +130,7 @@ like the title of the application or the address of a web API endpoint.
These configuration objects aren't always instances of a class. These configuration objects aren't always instances of a class.
They can be object literals, as shown in the following example. They can be object literals, as shown in the following example.
<code-example path="dependency-injection/src/app/app.config.ts" region="config" title="src/app/app.config.ts (excerpt)" linenums="false"> <code-example path="dependency-injection/src/app/app.config.ts" region="config" header="src/app/app.config.ts (excerpt)" linenums="false">
</code-example> </code-example>
{@a interface-not-valid-token} {@a interface-not-valid-token}
@ -157,13 +157,13 @@ There is no interface type information left for Angular to find at runtime.
One alternative is to provide and inject the configuration object in an NgModule like `AppModule`. One alternative is to provide and inject the configuration object in an NgModule like `AppModule`.
<code-example path="dependency-injection/src/app/app.module.ts" region="providers" title="src/app/app.module.ts (providers)"></code-example> <code-example path="dependency-injection/src/app/app.module.ts" region="providers" header="src/app/app.module.ts (providers)"></code-example>
Another solution to choosing a provider token for non-class dependencies is Another solution to choosing a provider token for non-class dependencies is
to define and use an `InjectionToken` object. to define and use an `InjectionToken` object.
The following example shows how to define such a token. The following example shows how to define such a token.
<code-example path="dependency-injection/src/app/app.config.ts" region="token" title="src/app/app.config.ts" linenums="false"> <code-example path="dependency-injection/src/app/app.config.ts" region="token" header="src/app/app.config.ts" linenums="false">
</code-example> </code-example>
The type parameter, while optional, conveys the dependency's type to developers and tooling. The type parameter, while optional, conveys the dependency's type to developers and tooling.
@ -177,7 +177,7 @@ Register the dependency provider using the `InjectionToken` object:
Now you can inject the configuration object into any constructor that needs it, with Now you can inject the configuration object into any constructor that needs it, with
the help of an `@Inject()` parameter decorator. the help of an `@Inject()` parameter decorator.
<code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" title="src/app/app.component.ts" linenums="false"> <code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" header="src/app/app.component.ts" linenums="false">
</code-example> </code-example>
<div class="alert-is-helpful"> <div class="alert-is-helpful">
@ -215,21 +215,21 @@ who is authorized and who isn't.
To resolve this, we give the `HeroService` constructor a boolean flag to control display of secret heroes. To resolve this, we give the `HeroService` constructor a boolean flag to control display of secret heroes.
<code-example path="dependency-injection/src/app/heroes/hero.service.ts" region="internals" title="src/app/heroes/hero.service.ts (excerpt)" linenums="false"> <code-example path="dependency-injection/src/app/heroes/hero.service.ts" region="internals" header="src/app/heroes/hero.service.ts (excerpt)" linenums="false">
</code-example> </code-example>
You can inject `Logger`, but you can't inject the `isAuthorized` flag. Instead, you can use a factory provider to create a new logger instance for `HeroService`. You can inject `Logger`, but you can't inject the `isAuthorized` flag. Instead, you can use a factory provider to create a new logger instance for `HeroService`.
A factory provider needs a factory function. A factory provider needs a factory function.
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="factory" title="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false"> <code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="factory" header="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false">
</code-example> </code-example>
Although `HeroService` has no access to `UserService`, the factory function does. Although `HeroService` has no access to `UserService`, the factory function does.
You inject both `Logger` and `UserService` into the factory provider You inject both `Logger` and `UserService` into the factory provider
and let the injector pass them along to the factory function. and let the injector pass them along to the factory function.
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="provider" title="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false"> <code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="provider" header="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false">
</code-example> </code-example>
* The `useFactory` field tells Angular that the provider is a factory function whose implementation is `heroServiceFactory`. * The `useFactory` field tells Angular that the provider is a factory function whose implementation is `heroServiceFactory`.
@ -248,10 +248,10 @@ The following shows the new and the old implementations side-by-side.
<code-tabs> <code-tabs>
<code-pane title="src/app/heroes/heroes.component (v3)" path="dependency-injection/src/app/heroes/heroes.component.ts"> <code-pane header="src/app/heroes/heroes.component (v3)" path="dependency-injection/src/app/heroes/heroes.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/heroes.component (v2)" path="dependency-injection/src/app/heroes/heroes.component.1.ts"> <code-pane header="src/app/heroes/heroes.component (v2)" path="dependency-injection/src/app/heroes/heroes.component.1.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -322,13 +322,13 @@ Thus, services provided at the NgModule or component level are not tree-shakable
The following example of non-tree-shakable providers in Angular configures a service provider for the injector of an NgModule. The following example of non-tree-shakable providers in Angular configures a service provider for the injector of an NgModule.
<code-example path="dependency-injection/src/app/tree-shaking/service-and-module.ts" title="src/app/tree-shaking/service-and-modules.ts" linenums="false"> </code-example> <code-example path="dependency-injection/src/app/tree-shaking/service-and-module.ts" header="src/app/tree-shaking/service-and-modules.ts" linenums="false"> </code-example>
This module can then be imported into your application module This module can then be imported into your application module
to make the service available for injection in your app, to make the service available for injection in your app,
as shown in the following example. as shown in the following example.
<code-example path="dependency-injection/src/app/tree-shaking/app.module.ts" title="src/app/tree-shaking/app.modules.ts" linenums="false"> </code-example> <code-example path="dependency-injection/src/app/tree-shaking/app.module.ts" header="src/app/tree-shaking/app.modules.ts" linenums="false"> </code-example>
When `ngc` runs, it compiles `AppModule` into a module factory, which contains definitions for all the providers declared in all the modules it includes. At runtime, this factory becomes an injector that instantiates these services. When `ngc` runs, it compiles `AppModule` into a module factory, which contains definitions for all the providers declared in all the modules it includes. At runtime, this factory becomes an injector that instantiates these services.
@ -340,11 +340,11 @@ You can make a provider tree-shakable by specifying it in the `@Injectable()` de
The following example shows the tree-shakable equivalent to the `ServiceModule` example above. The following example shows the tree-shakable equivalent to the `ServiceModule` example above.
<code-example path="dependency-injection/src/app/tree-shaking/service.ts" title="src/app/tree-shaking/service.ts" linenums="false"> </code-example> <code-example path="dependency-injection/src/app/tree-shaking/service.ts" header="src/app/tree-shaking/service.ts" linenums="false"> </code-example>
The service can be instantiated by configuring a factory function, as in the following example. The service can be instantiated by configuring a factory function, as in the following example.
<code-example path="dependency-injection/src/app/tree-shaking/service.0.ts" title="src/app/tree-shaking/service.0.ts" linenums="false"> </code-example> <code-example path="dependency-injection/src/app/tree-shaking/service.0.ts" header="src/app/tree-shaking/service.0.ts" linenums="false"> </code-example>
<div class="alert-is-helpful"> <div class="alert-is-helpful">

View File

@ -19,16 +19,16 @@ Start by reviewing this simplified version of the _heroes_ feature
from the [The Tour of Heroes](tutorial/). This simple version doesn't use DI; we'll walk through converting it to do so. from the [The Tour of Heroes](tutorial/). This simple version doesn't use DI; we'll walk through converting it to do so.
<code-tabs> <code-tabs>
<code-pane title="src/app/heroes/heroes.component.ts" path="dependency-injection/src/app/heroes/heroes.component.1.ts" region="v1"> <code-pane header="src/app/heroes/heroes.component.ts" path="dependency-injection/src/app/heroes/heroes.component.1.ts" region="v1">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/hero-list.component.ts" path="dependency-injection/src/app/heroes/hero-list.component.1.ts"> <code-pane header="src/app/heroes/hero-list.component.ts" path="dependency-injection/src/app/heroes/hero-list.component.1.ts">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/hero.ts" path="dependency-injection/src/app/heroes/hero.ts"> <code-pane header="src/app/heroes/hero.ts" path="dependency-injection/src/app/heroes/hero.ts">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/mock-heroes.ts" path="dependency-injection/src/app/heroes/mock-heroes.ts"> <code-pane header="src/app/heroes/mock-heroes.ts" path="dependency-injection/src/app/heroes/mock-heroes.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -39,7 +39,7 @@ Its only purpose is to display `HeroListComponent`, which displays a list of her
This version of the `HeroListComponent` gets heroes from the `HEROES` array, an in-memory collection This version of the `HeroListComponent` gets heroes from the `HEROES` array, an in-memory collection
defined in a separate `mock-heroes` file. defined in a separate `mock-heroes` file.
<code-example title="src/app/heroes/hero-list.component.ts (class)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts" region="class"> <code-example header="src/app/heroes/hero-list.component.ts (class)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts" region="class">
</code-example> </code-example>
This approach works for prototyping, but is not robust or maintainable. This approach works for prototyping, but is not robust or maintainable.
@ -76,12 +76,12 @@ ng generate service heroes/hero
The command creates the following `HeroService` skeleton. The command creates the following `HeroService` skeleton.
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" title="src/app/heroes/hero.service.ts (CLI-generated)"> <code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" header="src/app/heroes/hero.service.ts (CLI-generated)">
</code-example> </code-example>
The `@Injectable()` is an essential ingredient in every Angular service definition. The rest of the class has been written to expose a `getHeroes` method that returns the same mock data as before. (A real app would probably get its data asynchronously from a remote server, but we'll ignore that to focus on the mechanics of injecting the service.) The `@Injectable()` is an essential ingredient in every Angular service definition. The rest of the class has been written to expose a `getHeroes` method that returns the same mock data as before. (A real app would probably get its data asynchronously from a remote server, but we'll ignore that to focus on the mechanics of injecting the service.)
<code-example path="dependency-injection/src/app/heroes/hero.service.3.ts" title="src/app/heroes/hero.service.ts"> <code-example path="dependency-injection/src/app/heroes/hero.service.3.ts" header="src/app/heroes/hero.service.ts">
</code-example> </code-example>
@ -147,7 +147,7 @@ In order for `HeroListComponent` to get heroes from `HeroService`, it needs to a
You can tell Angular to inject a dependency in a component's constructor by specifying a **constructor parameter with the dependency type**. Here's the `HeroListComponent` constructor, asking for the `HeroService` to be injected. You can tell Angular to inject a dependency in a component's constructor by specifying a **constructor parameter with the dependency type**. Here's the `HeroListComponent` constructor, asking for the `HeroService` to be injected.
<code-example title="src/app/heroes/hero-list.component (constructor signature)" path="dependency-injection/src/app/heroes/hero-list.component.ts" <code-example header="src/app/heroes/hero-list.component (constructor signature)" path="dependency-injection/src/app/heroes/hero-list.component.ts"
region="ctor-signature"> region="ctor-signature">
</code-example> </code-example>
@ -155,10 +155,10 @@ Of course, `HeroListComponent` should do something with the injected `HeroServic
Here's the revised component, making use of the injected service, side-by-side with the previous version for comparison. Here's the revised component, making use of the injected service, side-by-side with the previous version for comparison.
<code-tabs> <code-tabs>
<code-pane title="hero-list.component (with DI)" path="dependency-injection/src/app/heroes/hero-list.component.2.ts"> <code-pane header="hero-list.component (with DI)" path="dependency-injection/src/app/heroes/hero-list.component.2.ts">
</code-pane> </code-pane>
<code-pane title="hero-list.component (without DI)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts"> <code-pane header="hero-list.component (without DI)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -197,7 +197,7 @@ Listing dependencies as constructor parameters may be all you need to test appli
For example, you can create a new `HeroListComponent` with a mock service that you can manipulate For example, you can create a new `HeroListComponent` with a mock service that you can manipulate
under test. under test.
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" title="src/app/test.component.ts" linenums="false"> <code-example path="dependency-injection/src/app/test.component.ts" region="spec" header="src/app/test.component.ts" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -217,13 +217,13 @@ Here is the revised `HeroService` that injects `Logger`, side by side with the p
<code-tabs> <code-tabs>
<code-pane title="src/app/heroes/hero.service (v2)" path="dependency-injection/src/app/heroes/hero.service.2.ts"> <code-pane header="src/app/heroes/hero.service (v2)" path="dependency-injection/src/app/heroes/hero.service.2.ts">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/hero.service (v1)" path="dependency-injection/src/app/heroes/hero.service.1.ts"> <code-pane header="src/app/heroes/hero.service (v1)" path="dependency-injection/src/app/heroes/hero.service.1.ts">
</code-pane> </code-pane>
<code-pane title="src/app/logger.service" <code-pane header="src/app/logger.service"
path="dependency-injection/src/app/logger.service.ts"> path="dependency-injection/src/app/logger.service.ts">
</code-pane> </code-pane>
@ -260,14 +260,14 @@ In simple examples, the dependency value is an *instance*, and
the class *type* serves as its own lookup key. the class *type* serves as its own lookup key.
Here you get a `HeroService` directly from the injector by supplying the `HeroService` type as the token: Here you get a `HeroService` directly from the injector by supplying the `HeroService` type as the token:
<code-example path="dependency-injection/src/app/injector.component.ts" region="get-hero-service" title="src/app/injector.component.ts" linenums="false"> <code-example path="dependency-injection/src/app/injector.component.ts" region="get-hero-service" header="src/app/injector.component.ts" linenums="false">
</code-example> </code-example>
The behavior is similar when you write a constructor that requires an injected class-based dependency. The behavior is similar when you write a constructor that requires an injected class-based dependency.
When you define a constructor parameter with the `HeroService` class type, When you define a constructor parameter with the `HeroService` class type,
Angular knows to inject the service associated with that `HeroService` class token: Angular knows to inject the service associated with that `HeroService` class token:
<code-example path="dependency-injection/src/app/heroes/hero-list.component.ts" region="ctor-signature" title="src/app/heroes/hero-list.component.ts"> <code-example path="dependency-injection/src/app/heroes/hero-list.component.ts" region="ctor-signature" header="src/app/heroes/hero-list.component.ts">
</code-example> </code-example>
Many dependency values are provided by classes, but not all. The expanded *provide* object lets you associate different kinds of providers with a DI token. Many dependency values are provided by classes, but not all. The expanded *provide* object lets you associate different kinds of providers with a DI token.

View File

@ -42,7 +42,7 @@ changing the template and the body of the component.
When you're done, it should look like this: When you're done, it should look like this:
<code-example path="displaying-data/src/app/app.component.1.ts" title="src/app/app.component.ts"> <code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts">
</code-example> </code-example>
@ -54,7 +54,7 @@ The template displays the two component properties using double curly brace
interpolation: interpolation:
<code-example path="displaying-data/src/app/app.component.1.ts" linenums="false" title="src/app/app.component.ts (template)" region="template"> <code-example path="displaying-data/src/app/app.component.1.ts" linenums="false" header="src/app/app.component.ts (template)" region="template">
</code-example> </code-example>
@ -98,7 +98,7 @@ The CSS `selector` in the `@Component` decorator specifies an element named `<ap
That element is a placeholder in the body of your `index.html` file: That element is a placeholder in the body of your `index.html` file:
<code-example path="displaying-data/src/index.html" linenums="false" title="src/index.html (body)" region="body"> <code-example path="displaying-data/src/index.html" linenums="false" header="src/index.html (body)" region="body">
</code-example> </code-example>
@ -164,7 +164,7 @@ This app uses more terse "variable assignment" style simply for brevity.
To display a list of heroes, begin by adding an array of hero names to the component and redefine `myHero` to be the first name in the array. To display a list of heroes, begin by adding an array of hero names to the component and redefine `myHero` to be the first name in the array.
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (class)" region="class"> <code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" header="src/app/app.component.ts (class)" region="class">
</code-example> </code-example>
@ -174,7 +174,7 @@ Now use the Angular `ngFor` directive in the template to display
each item in the `heroes` list. each item in the `heroes` list.
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (template)" region="template"> <code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" header="src/app/app.component.ts (template)" region="template">
</code-example> </code-example>
@ -185,7 +185,7 @@ in the `<li>` element is the Angular "repeater" directive.
It marks that `<li>` element (and its children) as the "repeater template": It marks that `<li>` element (and its children) as the "repeater template":
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (li)" region="li"> <code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" header="src/app/app.component.ts (li)" region="li">
</code-example> </code-example>
@ -252,7 +252,7 @@ of hero names into an array of `Hero` objects. For that you'll need a `Hero` cla
With the following code: With the following code:
<code-example path="displaying-data/src/app/hero.ts" linenums="false" title="src/app/hero.ts"> <code-example path="displaying-data/src/app/hero.ts" linenums="false" header="src/app/hero.ts">
</code-example> </code-example>
@ -266,7 +266,7 @@ The declaration of the constructor parameters takes advantage of a TypeScript sh
Consider the first parameter: Consider the first parameter:
<code-example path="displaying-data/src/app/hero.ts" linenums="false" title="src/app/hero.ts (id)" region="id"> <code-example path="displaying-data/src/app/hero.ts" linenums="false" header="src/app/hero.ts (id)" region="id">
</code-example> </code-example>
@ -286,7 +286,7 @@ After importing the `Hero` class, the `AppComponent.heroes` property can return
of `Hero` objects: of `Hero` objects:
<code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" title="src/app/app.component.ts (heroes)" region="heroes"> <code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" header="src/app/app.component.ts (heroes)" region="heroes">
</code-example> </code-example>
@ -297,7 +297,7 @@ At the moment it displays the hero's `id` and `name`.
Fix that to display only the hero's `name` property. Fix that to display only the hero's `name` property.
<code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" title="src/app/app.component.ts (template)" region="template"> <code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" header="src/app/app.component.ts (template)" region="template">
</code-example> </code-example>
@ -317,7 +317,7 @@ The Angular `ngIf` directive inserts or removes an element based on a _truthy/fa
To see it in action, add the following paragraph at the bottom of the template: To see it in action, add the following paragraph at the bottom of the template:
<code-example path="displaying-data/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts (message)" region="message"> <code-example path="displaying-data/src/app/app.component.ts" linenums="false" header="src/app/app.component.ts (message)" region="message">
</code-example> </code-example>
@ -375,19 +375,19 @@ Here's the final code:
<code-tabs> <code-tabs>
<code-pane title="src/app/app.component.ts" path="displaying-data/src/app/app.component.ts" region="final"> <code-pane header="src/app/app.component.ts" path="displaying-data/src/app/app.component.ts" region="final">
</code-pane> </code-pane>
<code-pane title="src/app/hero.ts" path="displaying-data/src/app/hero.ts"> <code-pane header="src/app/hero.ts" path="displaying-data/src/app/hero.ts">
</code-pane> </code-pane>
<code-pane title="src/app/app.module.ts" path="displaying-data/src/app/app.module.ts"> <code-pane header="src/app/app.module.ts" path="displaying-data/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="main.ts" path="displaying-data/src/main.ts"> <code-pane header="main.ts" path="displaying-data/src/main.ts">
</code-pane> </code-pane>

View File

@ -310,22 +310,22 @@ _This_ "Authors Doc Style Guide" has its own sample application, located in the
The following _code-example_ displays the sample's `app.module.ts`. The following _code-example_ displays the sample's `app.module.ts`.
<code-example path="docs-style-guide/src/app/app.module.ts" title="src/app/app.module.ts"></code-example> <code-example path="docs-style-guide/src/app/app.module.ts" header="src/app/app.module.ts"></code-example>
Here's the brief markup that produced that lengthy snippet: Here's the brief markup that produced that lengthy snippet:
```html ```html
<code-example <code-example
path="docs-style-guide/src/app/app.module.ts" path="docs-style-guide/src/app/app.module.ts"
title="src/app/app.module.ts"> header="src/app/app.module.ts">
</code-example> </code-example>
``` ```
You identified the snippet's source file by setting the `path` attribute to sample folder's location _within_ `content/examples`. You identified the snippet's source file by setting the `path` attribute to sample folder's location _within_ `content/examples`.
In this example, that path is `docs-style-guide/src/app/app.module.ts`. In this example, that path is `docs-style-guide/src/app/app.module.ts`.
You added a header to tell the reader where to find the file by setting the `title` attribute. You added a header to tell the reader where to find the file by setting the `header` attribute.
Following convention, you set the `title` attribute to the file's location within the sample's root folder. Following convention, you set the `header` attribute to the file's location within the sample's root folder.
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -343,7 +343,7 @@ If you want to include an ignored code file in your project and display it in a
The preferred way to un-ignore a file is to update the `content/examples/.gitignore` like this: The preferred way to un-ignore a file is to update the `content/examples/.gitignore` like this:
<code-example title="content/examples/.gitignore"> <code-example header="content/examples/.gitignore">
# my-guide # my-guide
!my-guide/src/something.js !my-guide/src/something.js
!my-guide/more-javascript*.js !my-guide/more-javascript*.js
@ -357,7 +357,7 @@ You control the _code-example_ output by setting one or more of its attributes:
* `path`- the path to the file in the `content/examples` folder. * `path`- the path to the file in the `content/examples` folder.
* `title`- the header of the code listing. * `header`- the header of the code listing.
* `region`- displays the source file fragment with that region name; regions are identified by _docregion_ markup in the source file, as explained [below](#region "Displaying a code fragment"). * `region`- displays the source file fragment with that region name; regions are identified by _docregion_ markup in the source file, as explained [below](#region "Displaying a code fragment").
@ -395,7 +395,7 @@ A couple of observations:
1. The `region` value, `"class"`, is the name of the `#docregion` in the source file. Confirm that by looking at `content/examples/docs-style-guide/src/app/app.module.ts` 1. The `region` value, `"class"`, is the name of the `#docregion` in the source file. Confirm that by looking at `content/examples/docs-style-guide/src/app/app.module.ts`
1. Omitting the `title` is fine when the source of the fragment is obvious. We just said that this is a fragment of the `app.module.ts` file which was displayed immediately above, in full, with a header. 1. Omitting the `header` is fine when the source of the fragment is obvious. We just said that this is a fragment of the `app.module.ts` file which was displayed immediately above, in full, with a header.
There's no need to repeat the header. There's no need to repeat the header.
1. The line numbers disappeared. By default, the doc viewer omits line numbers when there are fewer than 10 lines of code; it adds line numbers after that. You can turn line numbers on or off explicitly by setting the `linenums` attribute. 1. The line numbers disappeared. By default, the doc viewer omits line numbers when there are fewer than 10 lines of code; it adds line numbers after that. You can turn line numbers on or off explicitly by setting the `linenums` attribute.
@ -415,11 +415,11 @@ Here's the markup for an "avoid" example in the
<code-example <code-example
path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts" path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts"
region="example" region="example"
title="app/heroes/hero-button/hero-button.component.ts"> header="app/heroes/hero-button/hero-button.component.ts">
</code-example> </code-example>
``` ```
<code-example path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/hero-button/hero-button.component.ts"> <code-example path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" header="app/heroes/hero-button/hero-button.component.ts">
</code-example> </code-example>
{@a code-tabs} {@a code-tabs}
@ -434,29 +434,29 @@ Code tabs display code much like _code examples_ do. The added advantage is tha
#### Code-pane attributes #### Code-pane attributes
* `path` - a file in the content/examples folder * `path` - a file in the content/examples folder
* `title` - seen in the header of a tab * `header` - seen in the header of a tab
* `linenums` - overrides the `linenums` property at the `code-tabs` level for this particular pane. The value can be `true`, `false` or a number indicating the starting line number. If not specified, line numbers are enabled only when the number of lines of code are greater than 10. * `linenums` - overrides the `linenums` property at the `code-tabs` level for this particular pane. The value can be `true`, `false` or a number indicating the starting line number. If not specified, line numbers are enabled only when the number of lines of code are greater than 10.
The next example displays multiple code tabs, each with its own title. The next example displays multiple code tabs, each with its own header.
It demonstrates control over display of line numbers at both the `<code-tabs>` and `<code-pane>` levels. It demonstrates control over display of line numbers at both the `<code-tabs>` and `<code-pane>` levels.
<code-tabs linenums="false"> <code-tabs linenums="false">
<code-pane <code-pane
title="app.component.html" header="app.component.html"
path="docs-style-guide/src/app/app.component.html"> path="docs-style-guide/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="app.component.ts" header="app.component.ts"
path="docs-style-guide/src/app/app.component.ts" path="docs-style-guide/src/app/app.component.ts"
linenums="true"> linenums="true">
</code-pane> </code-pane>
<code-pane <code-pane
title="app.component.css (heroes)" header="app.component.css (heroes)"
path="docs-style-guide/src/app/app.component.css" path="docs-style-guide/src/app/app.component.css"
region="heroes"> region="heroes">
</code-pane> </code-pane>
<code-pane <code-pane
title="package.json (scripts)" header="package.json (scripts)"
path="docs-style-guide/package.1.json"> path="docs-style-guide/package.1.json">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -469,21 +469,21 @@ The `linenums` attribute in the second pane restores line numbering for _itself
```html ```html
<code-tabs linenums="false"> <code-tabs linenums="false">
<code-pane <code-pane
title="app.component.html" header="app.component.html"
path="docs-style-guide/src/app/app.component.html"> path="docs-style-guide/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="app.component.ts" header="app.component.ts"
path="docs-style-guide/src/app/app.component.ts" path="docs-style-guide/src/app/app.component.ts"
linenums="true"> linenums="true">
</code-pane> </code-pane>
<code-pane <code-pane
title="app.component.css (heroes)" header="app.component.css (heroes)"
path="docs-style-guide/src/app/app.component.css" path="docs-style-guide/src/app/app.component.css"
region="heroes"> region="heroes">
</code-pane> </code-pane>
<code-pane <code-pane
title="package.json (scripts)" header="package.json (scripts)"
path="docs-style-guide/package.1.json"> path="docs-style-guide/package.1.json">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -548,7 +548,7 @@ The `src/main.ts` is a simple example of a file with a single _#docregion_ at th
<code-example <code-example
path="docs-style-guide/src/main.ts" path="docs-style-guide/src/main.ts"
title="src/main.ts"></code-example> header="src/main.ts"></code-example>
</div> </div>
@ -622,12 +622,12 @@ Here's are the two corresponding code snippets displayed side-by-side.
<code-tabs> <code-tabs>
<code-pane <code-pane
title="app.component.ts (class)" header="app.component.ts (class)"
path="docs-style-guide/src/app/app.component.ts" path="docs-style-guide/src/app/app.component.ts"
region="class"> region="class">
</code-pane> </code-pane>
<code-pane <code-pane
title="app.component.ts (class-skeleton)" header="app.component.ts (class-skeleton)"
path="docs-style-guide/src/app/app.component.ts" path="docs-style-guide/src/app/app.component.ts"
region="class-skeleton"> region="class-skeleton">
</code-pane> </code-pane>
@ -660,12 +660,12 @@ Here's an example that excerpts certain scripts from `package.json` into a parti
<code-example <code-example
path="docs-style-guide/package.1.json" path="docs-style-guide/package.1.json"
title="package.json (selected scripts)"></code-example> header="package.json (selected scripts)"></code-example>
```html ```html
<code-example <code-example
path="docs-style-guide/package.1.json" path="docs-style-guide/package.1.json"
title="package.json (selected scripts)"></code-example> header="package.json (selected scripts)"></code-example>
``` ```
#### Partial file naming #### Partial file naming
@ -689,7 +689,7 @@ Remember to exclude these files from stackblitz by listing them in the `stackbli
<code-example <code-example
path="docs-style-guide/stackblitz.json" path="docs-style-guide/stackblitz.json"
title="stackblitz.json"></code-example> header="stackblitz.json"></code-example>
{@a live-examples} {@a live-examples}
## Live examples ## Live examples

View File

@ -35,7 +35,7 @@ The ad banner uses a helper directive called `AdDirective` to
mark valid insertion points in the template. mark valid insertion points in the template.
<code-example path="dynamic-component-loader/src/app/ad.directive.ts" title="src/app/ad.directive.ts" linenums="false"> <code-example path="dynamic-component-loader/src/app/ad.directive.ts" header="src/app/ad.directive.ts" linenums="false">
</code-example> </code-example>
@ -62,7 +62,7 @@ To apply the `AdDirective`, recall the selector from `ad.directive.ts`,
where to dynamically load components. where to dynamically load components.
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="ad-host" title="src/app/ad-banner.component.ts (template)" linenums="false"> <code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="ad-host" header="src/app/ad-banner.component.ts (template)" linenums="false">
</code-example> </code-example>
@ -91,7 +91,7 @@ With its `getAds()` method, `AdBannerComponent` cycles through the array of `AdI
and loads a new component every 3 seconds by calling `loadComponent()`. and loads a new component every 3 seconds by calling `loadComponent()`.
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="class" title="src/app/ad-banner.component.ts (excerpt)" linenums="false"> <code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="class" header="src/app/ad-banner.component.ts (excerpt)" linenums="false">
</code-example> </code-example>
@ -150,7 +150,7 @@ dynamically loaded components since they load at runtime.
To ensure that the compiler still generates a factory, To ensure that the compiler still generates a factory,
add dynamically loaded components to the `NgModule`'s `entryComponents` array: add dynamically loaded components to the `NgModule`'s `entryComponents` array:
<code-example path="dynamic-component-loader/src/app/app.module.ts" region="entry-components" title="src/app/app.module.ts (entry components)" linenums="false"> <code-example path="dynamic-component-loader/src/app/app.module.ts" region="entry-components" header="src/app/app.module.ts (entry components)" linenums="false">
</code-example> </code-example>
@ -169,15 +169,15 @@ Here are two sample components and the `AdComponent` interface for reference:
<code-tabs> <code-tabs>
<code-pane title="hero-job-ad.component.ts" path="dynamic-component-loader/src/app/hero-job-ad.component.ts"> <code-pane header="hero-job-ad.component.ts" path="dynamic-component-loader/src/app/hero-job-ad.component.ts">
</code-pane> </code-pane>
<code-pane title="hero-profile.component.ts" path="dynamic-component-loader/src/app/hero-profile.component.ts"> <code-pane header="hero-profile.component.ts" path="dynamic-component-loader/src/app/hero-profile.component.ts">
</code-pane> </code-pane>
<code-pane title="ad.component.ts" path="dynamic-component-loader/src/app/ad.component.ts"> <code-pane header="ad.component.ts" path="dynamic-component-loader/src/app/ad.component.ts">
</code-pane> </code-pane>

View File

@ -40,11 +40,11 @@ Bootstrap the `AppModule` in `main.ts`.
<code-tabs> <code-tabs>
<code-pane title="app.module.ts" path="dynamic-form/src/app/app.module.ts"> <code-pane header="app.module.ts" path="dynamic-form/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="main.ts" path="dynamic-form/src/main.ts"> <code-pane header="main.ts" path="dynamic-form/src/main.ts">
</code-pane> </code-pane>
@ -62,7 +62,7 @@ The _question_ is the most fundamental object in the model.
The following `QuestionBase` is a fundamental question class. The following `QuestionBase` is a fundamental question class.
<code-example path="dynamic-form/src/app/question-base.ts" title="src/app/question-base.ts"> <code-example path="dynamic-form/src/app/question-base.ts" header="src/app/question-base.ts">
</code-example> </code-example>
@ -77,7 +77,7 @@ appropriate controls dynamically.
via the `type` property. via the `type` property.
<code-example path="dynamic-form/src/app/question-textbox.ts" title="src/app/question-textbox.ts" linenums="false"> <code-example path="dynamic-form/src/app/question-textbox.ts" header="src/app/question-textbox.ts" linenums="false">
</code-example> </code-example>
@ -86,7 +86,7 @@ via the `type` property.
`DropdownQuestion` presents a list of choices in a select box. `DropdownQuestion` presents a list of choices in a select box.
<code-example path="dynamic-form/src/app/question-dropdown.ts" title="src/app/question-dropdown.ts" linenums="false"> <code-example path="dynamic-form/src/app/question-dropdown.ts" header="src/app/question-dropdown.ts" linenums="false">
</code-example> </code-example>
@ -97,7 +97,7 @@ 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.
<code-example path="dynamic-form/src/app/question-control.service.ts" title="src/app/question-control.service.ts" linenums="false"> <code-example path="dynamic-form/src/app/question-control.service.ts" header="src/app/question-control.service.ts" linenums="false">
</code-example> </code-example>
@ -112,11 +112,11 @@ to create components to represent the dynamic form.
<code-tabs> <code-tabs>
<code-pane title="dynamic-form.component.html" path="dynamic-form/src/app/dynamic-form.component.html"> <code-pane header="dynamic-form.component.html" path="dynamic-form/src/app/dynamic-form.component.html">
</code-pane> </code-pane>
<code-pane title="dynamic-form.component.ts" path="dynamic-form/src/app/dynamic-form.component.ts"> <code-pane header="dynamic-form.component.ts" path="dynamic-form/src/app/dynamic-form.component.ts">
</code-pane> </code-pane>
@ -132,11 +132,11 @@ question based on values in the data-bound question object.
<code-tabs> <code-tabs>
<code-pane title="dynamic-form-question.component.html" path="dynamic-form/src/app/dynamic-form-question.component.html"> <code-pane header="dynamic-form-question.component.html" path="dynamic-form/src/app/dynamic-form-question.component.html">
</code-pane> </code-pane>
<code-pane title="dynamic-form-question.component.ts" path="dynamic-form/src/app/dynamic-form-question.component.ts"> <code-pane header="dynamic-form-question.component.ts" path="dynamic-form/src/app/dynamic-form-question.component.ts">
</code-pane> </code-pane>
@ -169,7 +169,7 @@ directly since you imported `ReactiveFormsModule` from `AppModule`.
and removing objects from the `questions` array. and removing objects from the `questions` array.
<code-example path="dynamic-form/src/app/question.service.ts" title="src/app/question.service.ts"> <code-example path="dynamic-form/src/app/question.service.ts" header="src/app/question.service.ts">
</code-example> </code-example>
@ -178,7 +178,7 @@ directly since you imported `ReactiveFormsModule` from `AppModule`.
Finally, display an instance of the form in the `AppComponent` shell. Finally, display an instance of the form in the `AppComponent` shell.
<code-example path="dynamic-form/src/app/app.component.ts" title="app.component.ts"> <code-example path="dynamic-form/src/app/app.component.ts" header="app.component.ts">
</code-example> </code-example>

View File

@ -142,19 +142,19 @@ For comparison, the demo shows both methods. One button adds the popup using the
<code-tabs> <code-tabs>
<code-pane title="popup.component.ts" path="elements/src/app/popup.component.ts"> <code-pane header="popup.component.ts" path="elements/src/app/popup.component.ts">
</code-pane> </code-pane>
<code-pane title="popup.service.ts" path="elements/src/app/popup.service.ts"> <code-pane header="popup.service.ts" path="elements/src/app/popup.service.ts">
</code-pane> </code-pane>
<code-pane title="app.module.ts" path="elements/src/app/app.module.ts"> <code-pane header="app.module.ts" path="elements/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="app.component.ts" path="elements/src/app/app.component.ts"> <code-pane header="app.component.ts" path="elements/src/app/app.component.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>

View File

@ -72,7 +72,7 @@ ng generate component customer-dashboard/CustomerDashboard
This generates a folder for the new component within the customer-dashboard folder and updates the feature module with the `CustomerDashboardComponent` info: This generates a folder for the new component within the customer-dashboard folder and updates the feature module with the `CustomerDashboardComponent` info:
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="customer-dashboard-component" title="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false"> <code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="customer-dashboard-component" header="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false">
</code-example> </code-example>
@ -83,7 +83,7 @@ The `CustomerDashboardComponent` is now in the JavaScript import list at the top
To incorporate the feature module into your app, you have to let the root module, `app.module.ts`, know about it. Notice the `CustomerDashboardModule` export at the bottom of `customer-dashboard.module.ts`. This exposes it so that other modules can get to it. To import it into the `AppModule`, add it to the imports in `app.module.ts` and to the `imports` array: To incorporate the feature module into your app, you have to let the root module, `app.module.ts`, know about it. Notice the `CustomerDashboardModule` export at the bottom of `customer-dashboard.module.ts`. This exposes it so that other modules can get to it. To import it into the `AppModule`, add it to the imports in `app.module.ts` and to the `imports` array:
<code-example path="feature-modules/src/app/app.module.ts" region="app-module" title="src/app/app.module.ts" linenums="false"> <code-example path="feature-modules/src/app/app.module.ts" region="app-module" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
@ -94,20 +94,20 @@ Now the `AppModule` knows about the feature module. If you were to add any servi
When the CLI generated the `CustomerDashboardComponent` for the feature module, it included a template, `customer-dashboard.component.html`, with the following markup: When the CLI generated the `CustomerDashboardComponent` for the feature module, it included a template, `customer-dashboard.component.html`, with the following markup:
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" region="feature-template" title="src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" linenums="false"> <code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" region="feature-template" header="src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" linenums="false">
</code-example> </code-example>
To see this HTML in the `AppComponent`, you first have to export the `CustomerDashboardComponent` in the `CustomerDashboardModule`. In `customer-dashboard.module.ts`, just beneath the `declarations` array, add an `exports` array containing `CustomerDashboardModule`: To see this HTML in the `AppComponent`, you first have to export the `CustomerDashboardComponent` in the `CustomerDashboardModule`. In `customer-dashboard.module.ts`, just beneath the `declarations` array, add an `exports` array containing `CustomerDashboardModule`:
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="component-exports" title="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false"> <code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="component-exports" header="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false">
</code-example> </code-example>
Next, in the `AppComponent`, `app.component.html`, add the tag `<app-customer-dashboard>`: Next, in the `AppComponent`, `app.component.html`, add the tag `<app-customer-dashboard>`:
<code-example path="feature-modules/src/app/app.component.html" region="app-component-template" title="src/app/app.component.html" linenums="false"> <code-example path="feature-modules/src/app/app.component.html" region="app-component-template" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>

View File

@ -29,7 +29,7 @@ either a list of validation errors, which results in an INVALID status, or null,
You can then inspect the control's state by exporting `ngModel` to a local template variable. You can then inspect the control's state by exporting `ngModel` to a local template variable.
The following example exports `NgModel` into a variable called `name`: The following example exports `NgModel` into a variable called `name`:
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-with-error-msg" title="template/hero-form-template.component.html (name)" linenums="false"> <code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-with-error-msg" header="template/hero-form-template.component.html (name)" linenums="false">
</code-example> </code-example>
@ -92,7 +92,7 @@ built-in validators&mdash;this time, in function form. See below:
{@a reactive-component-class} {@a reactive-component-class}
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="form-group" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false"> <code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="form-group" header="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
</code-example> </code-example>
Note that: Note that:
@ -106,7 +106,7 @@ for the template.
If you look at the template for the name input again, it is fairly similar to the template-driven example. If you look at the template for the name input again, it is fairly similar to the template-driven example.
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="name-with-error-msg" title="reactive/hero-form-reactive.component.html (name with error msg)" linenums="false"> <code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="name-with-error-msg" header="reactive/hero-form-reactive.component.html (name with error msg)" linenums="false">
</code-example> </code-example>
Key takeaways: Key takeaways:
@ -125,7 +125,7 @@ Consider the `forbiddenNameValidator` function from previous
[examples](guide/form-validation#reactive-component-class) in [examples](guide/form-validation#reactive-component-class) in
this guide. Here's what the definition of that function looks like: this guide. Here's what the definition of that function looks like:
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="custom-validator" title="shared/forbidden-name.directive.ts (forbiddenNameValidator)" linenums="false"> <code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="custom-validator" header="shared/forbidden-name.directive.ts (forbiddenNameValidator)" linenums="false">
</code-example> </code-example>
The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name and returns a validator function. The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name and returns a validator function.
@ -148,7 +148,7 @@ at which point the form uses the last value emitted for validation.
In reactive forms, custom validators are fairly simple to add. All you have to do is pass the function directly In reactive forms, custom validators are fairly simple to add. All you have to do is pass the function directly
to the `FormControl`. to the `FormControl`.
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="custom-validator" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false"> <code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="custom-validator" header="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
</code-example> </code-example>
### Adding to template-driven forms ### Adding to template-driven forms
@ -161,19 +161,19 @@ The corresponding `ForbiddenValidatorDirective` serves as a wrapper around the `
Angular recognizes the directive's role in the validation process because the directive registers itself Angular recognizes the directive's role in the validation process because the directive registers itself
with the `NG_VALIDATORS` provider, a provider with an extensible collection of validators. with the `NG_VALIDATORS` provider, a provider with an extensible collection of validators.
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive-providers" title="shared/forbidden-name.directive.ts (providers)" linenums="false"> <code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive-providers" header="shared/forbidden-name.directive.ts (providers)" linenums="false">
</code-example> </code-example>
The directive class then implements the `Validator` interface, so that it can easily integrate The directive class then implements the `Validator` interface, so that it can easily integrate
with Angular forms. Here is the rest of the directive to help you get an idea of how it all with Angular forms. Here is the rest of the directive to help you get an idea of how it all
comes together: comes together:
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive" title="shared/forbidden-name.directive.ts (directive)"> <code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive" header="shared/forbidden-name.directive.ts (directive)">
</code-example> </code-example>
Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector, `appForbiddenName`, to any input element to activate it. For example: Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector, `appForbiddenName`, to any input element to activate it. For example:
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-input" title="template/hero-form-template.component.html (forbidden-name-input)" linenums="false"> <code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-input" header="template/hero-form-template.component.html (forbidden-name-input)" linenums="false">
</code-example> </code-example>
@ -204,7 +204,7 @@ Like in AngularJS, Angular automatically mirrors many control properties onto th
The hero form uses the `.ng-valid` and `.ng-invalid` classes to The hero form uses the `.ng-valid` and `.ng-invalid` classes to
set the color of each form control's border. set the color of each form control's border.
<code-example path="form-validation/src/assets/forms.css" title="forms.css (status classes)"> <code-example path="form-validation/src/assets/forms.css" header="forms.css (status classes)">
</code-example> </code-example>
@ -245,7 +245,7 @@ const heroForm = new FormGroup({
The validator code is as follows: The validator code is as follows:
<code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-validator" title="shared/identity-revealed.directive.ts" linenums="false"> <code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-validator" header="shared/identity-revealed.directive.ts" linenums="false">
</code-example> </code-example>
The identity validator implements the `ValidatorFn` interface. It takes an Angular control object as an argument and returns either null if the form is valid, or `ValidationErrors` otherwise. The identity validator implements the `ValidatorFn` interface. It takes an Angular control object as an argument and returns either null if the form is valid, or `ValidationErrors` otherwise.
@ -255,7 +255,7 @@ First we retrieve the child controls by calling the `FormGroup`'s [get](api/form
If the values do not match, the hero's identity remains secret, and we can safely return null. Otherwise, the hero's identity is revealed and we must mark the form as invalid by returning an error object. If the values do not match, the hero's identity remains secret, and we can safely return null. Otherwise, the hero's identity is revealed and we must mark the form as invalid by returning an error object.
Next, to provide better user experience, we show an appropriate error message when the form is invalid. Next, to provide better user experience, we show an appropriate error message when the form is invalid.
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="cross-validation-error-message" title="reactive/hero-form-template.component.html" linenums="false"> <code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="cross-validation-error-message" header="reactive/hero-form-template.component.html" linenums="false">
</code-example> </code-example>
Note that we check if: Note that we check if:
@ -265,15 +265,15 @@ Note that we check if:
### Adding to template driven forms ### Adding to template driven forms
First we must create a directive that will wrap the validator function. We provide it as the validator using the `NG_VALIDATORS` token. If you are not sure why, or you do not fully understand the syntax, revisit the previous [section](guide/form-validation#adding-to-template-driven-forms). First we must create a directive that will wrap the validator function. We provide it as the validator using the `NG_VALIDATORS` token. If you are not sure why, or you do not fully understand the syntax, revisit the previous [section](guide/form-validation#adding-to-template-driven-forms).
<code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-directive" title="shared/identity-revealed.directive.ts" linenums="false"> <code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-directive" header="shared/identity-revealed.directive.ts" linenums="false">
</code-example> </code-example>
Next, we have to add the directive to the html template. Since the validator must be registered at the highest level in the form, we put the directive on the `form` tag. Next, we have to add the directive to the html template. Since the validator must be registered at the highest level in the form, we put the directive on the `form` tag.
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-register-validator" title="template/hero-form-template.component.html" linenums="false"> <code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-register-validator" header="template/hero-form-template.component.html" linenums="false">
</code-example> </code-example>
To provide better user experience, we show an appropriate error message when the form is invalid. To provide better user experience, we show an appropriate error message when the form is invalid.
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-error-message" title="template/hero-form-template.component.html" linenums="false"> <code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-error-message" header="template/hero-form-template.component.html" linenums="false">
</code-example> </code-example>
Note that we check if: Note that we check if:

View File

@ -169,7 +169,7 @@ The following tests use the favorite color components mentioned earlier to verif
The following test verifies the view to model data flow: The following test verifies the view to model data flow:
<code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.spec.ts" region="view-to-model" title="Favorite color test - view to model"> <code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.spec.ts" region="view-to-model" header="Favorite color test - view to model">
</code-example> </code-example>
The steps performed in the view to model test. The steps performed in the view to model test.
@ -180,7 +180,7 @@ The steps performed in the view to model test.
The following test verifies the model to view data flow: The following test verifies the model to view data flow:
<code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.spec.ts" region="model-to-view" title="Favorite color test - model to view"> <code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.spec.ts" region="model-to-view" header="Favorite color test - model to view">
</code-example> </code-example>
The steps performed in the model to view test. The steps performed in the model to view test.
@ -197,7 +197,7 @@ The following tests use the favorite color components mentioned earlier to verif
The following test verifies the view to model data flow: The following test verifies the view to model data flow:
<code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.spec.ts" region="view-to-model" title="Favorite color test - view to model"> <code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.spec.ts" region="view-to-model" header="Favorite color test - view to model">
</code-example> </code-example>
The steps performed in the view to model test. The steps performed in the view to model test.
@ -209,7 +209,7 @@ The steps performed in the view to model test.
The following test verifies the model to view data flow: The following test verifies the model to view data flow:
<code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.spec.ts" region="model-to-view" title="Favorite color test - model to view"> <code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.spec.ts" region="model-to-view" header="Favorite color test - model to view">
</code-example> </code-example>
The steps performed in the model to view test. The steps performed in the model to view test.

View File

@ -109,7 +109,7 @@ Using the Angular CLI, generate a new class named `Hero`:
With this content: With this content:
<code-example path="forms/src/app/hero.ts" title="src/app/hero.ts"> <code-example path="forms/src/app/hero.ts" header="src/app/hero.ts">
</code-example> </code-example>
@ -142,7 +142,7 @@ Using the Angular CLI, generate a new component named `HeroForm`:
With this content: With this content:
<code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" title="src/app/hero-form/hero-form.component.ts (v1)" region="v1"> <code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" header="src/app/hero-form/hero-form.component.ts (v1)" region="v1">
</code-example> </code-example>
@ -176,7 +176,7 @@ Because template-driven forms are in their own module, you need to add the `Form
Update it with the following: Update it with the following:
<code-example path="forms/src/app/app.module.ts" title="src/app/app.module.ts"> <code-example path="forms/src/app/app.module.ts" header="src/app/app.module.ts">
</code-example> </code-example>
@ -204,7 +204,7 @@ Update it with the following:
Replace the contents of its template with the following: Replace the contents of its template with the following:
<code-example path="forms/src/app/app.component.html" title="src/app/app.component.html"> <code-example path="forms/src/app/app.component.html" header="src/app/app.component.html">
</code-example> </code-example>
@ -221,7 +221,7 @@ Replace the contents of its template with the following:
Update the template file with the following contents: Update the template file with the following contents:
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="start" title="src/app/hero-form/hero-form.component.html"> <code-example path="forms/src/app/hero-form/hero-form.component.html" region="start" header="src/app/hero-form/hero-form.component.html">
</code-example> </code-example>
@ -259,7 +259,7 @@ Bootstrap gives the form a little style.
To add the stylesheet, open `styles.css` and add the following import line at the top: To add the stylesheet, open `styles.css` and add the following import line at the top:
<code-example path="forms/src/styles.1.css" linenums="false" title="src/styles.css"> <code-example path="forms/src/styles.1.css" linenums="false" header="src/styles.css">
</code-example> </code-example>
@ -274,7 +274,7 @@ a technique seen previously in the [Displaying Data](guide/displaying-data) page
Add the following HTML *immediately below* the *Alter Ego* group: Add the following HTML *immediately below* the *Alter Ego* group:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (powers)" region="powers"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (powers)" region="powers">
</code-example> </code-example>
@ -307,7 +307,7 @@ makes binding the form to the model easy.
Find the `<input>` tag for *Name* and update it like this: Find the `<input>` tag for *Name* and update it like this:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-1"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-1">
</code-example> </code-example>
@ -325,7 +325,7 @@ 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:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="template-variable"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="template-variable">
</code-example> </code-example>
@ -391,7 +391,7 @@ Then you can confirm that two-way data binding works *for the entire hero model*
After revision, the core of the form should look like this: After revision, the core of the form should look like this:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModel-2"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModel-2">
</code-example> </code-example>
@ -493,7 +493,7 @@ You can leverage those class names to change the appearance of the control.
Temporarily add a [template reference variable](guide/template-syntax#ref-vars) named `spy` Temporarily add a [template reference variable](guide/template-syntax#ref-vars) named `spy`
to the _Name_ `<input>` tag and use it to display the input's CSS classes. to the _Name_ `<input>` tag and use it to display the input's CSS classes.
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-2"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-2">
</code-example> </code-example>
@ -535,13 +535,13 @@ on the left of the input box:
You achieve this effect by adding these class definitions to a new `forms.css` file You achieve this effect by adding these class definitions to a new `forms.css` file
that you add to the project as a sibling to `index.html`: that you add to the project as a sibling to `index.html`:
<code-example path="forms/src/assets/forms.css" title="src/assets/forms.css"> <code-example path="forms/src/assets/forms.css" header="src/assets/forms.css">
</code-example> </code-example>
Update the `<head>` of `index.html` to include this style sheet: Update the `<head>` of `index.html` to include this style sheet:
<code-example path="forms/src/index.html" linenums="false" title="src/index.html (styles)" region="styles"> <code-example path="forms/src/index.html" linenums="false" header="src/index.html (styles)" region="styles">
</code-example> </code-example>
@ -564,7 +564,7 @@ To achieve this effect, extend the `<input>` tag with the following:
Here's an example of an error message added to the _name_ input box: Here's an example of an error message added to the _name_ input box:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="name-with-error-msg"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="name-with-error-msg">
</code-example> </code-example>
@ -583,7 +583,7 @@ Here you created a variable called `name` and gave it the value "ngModel".
You control visibility of the name error message by binding properties of the `name` You control visibility of the name error message by binding properties of the `name`
control to the message `<div>` element's `hidden` property. control to the message `<div>` element's `hidden` property.
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (hidden-error-msg)" region="hidden-error-msg"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (hidden-error-msg)" region="hidden-error-msg">
</code-example> </code-example>
@ -609,11 +609,11 @@ power to valid values.
Now you'll add a new hero in this form. Now you'll add a new hero in this form.
Place a *New Hero* button at the bottom of the form and bind its click event to a `newHero` component method. Place a *New Hero* button at the bottom of the form and bind its click event to a `newHero` component method.
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-no-reset" title="src/app/hero-form/hero-form.component.html (New Hero button)"> <code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-no-reset" header="src/app/hero-form/hero-form.component.html (New Hero button)">
</code-example> </code-example>
<code-example path="forms/src/app/hero-form/hero-form.component.ts" region="new-hero" title="src/app/hero-form/hero-form.component.ts (New Hero method)" linenums="false"> <code-example path="forms/src/app/hero-form/hero-form.component.ts" region="new-hero" header="src/app/hero-form/hero-form.component.ts (New Hero method)" linenums="false">
</code-example> </code-example>
@ -634,7 +634,7 @@ Replacing the hero object *did not restore the pristine state* of the form contr
You have to clear all of the flags imperatively, which you can do You have to clear all of the flags imperatively, which you can do
by calling the form's `reset()` method after calling the `newHero()` method. by calling the form's `reset()` method after calling the `newHero()` method.
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-form-reset" title="src/app/hero-form/hero-form.component.html (Reset the form)"> <code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-form-reset" header="src/app/hero-form/hero-form.component.html (Reset the form)">
</code-example> </code-example>
@ -651,7 +651,7 @@ A "form submit" is useless at the moment.
To make it useful, bind the form's `ngSubmit` event property To make it useful, bind the form's `ngSubmit` event property
to the hero form component's `onSubmit()` method: to the hero form component's `onSubmit()` method:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (ngSubmit)" region="ngSubmit"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (ngSubmit)" region="ngSubmit">
</code-example> </code-example>
@ -664,7 +664,7 @@ You'll bind the form's overall validity via
the `heroForm` variable to the button's `disabled` property the `heroForm` variable to the button's `disabled` property
using an event binding. Here's the code: using an event binding. Here's the code:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (submit-button)" region="submit-button"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (submit-button)" region="submit-button">
</code-example> </code-example>
@ -703,7 +703,7 @@ hide the data entry area and display something else.
Wrap the form in a `<div>` and bind Wrap the form in a `<div>` and bind
its `hidden` property to the `HeroFormComponent.submitted` property. its `hidden` property to the `HeroFormComponent.submitted` property.
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="edit-div"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="edit-div">
</code-example> </code-example>
@ -711,7 +711,7 @@ The main form is visible from the start because the
`submitted` property is false until you submit the form, `submitted` property is false until you submit the form,
as this fragment from the `HeroFormComponent` shows: as this fragment from the `HeroFormComponent` shows:
<code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" title="src/app/hero-form/hero-form.component.ts (submitted)" region="submitted"> <code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" header="src/app/hero-form/hero-form.component.ts (submitted)" region="submitted">
</code-example> </code-example>
@ -721,7 +721,7 @@ as planned.
Now the app needs to show something else while the form is in the submitted state. Now the app needs to show something else while the form is in the submitted state.
Add the following HTML below the `<div>` wrapper you just wrote: Add the following HTML below the `<div>` wrapper you just wrote:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="submitted"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="submitted">
</code-example> </code-example>
@ -752,35 +752,35 @@ Heres the code for the final version of the application:
<code-tabs> <code-tabs>
<code-pane title="hero-form/hero-form.component.ts" path="forms/src/app/hero-form/hero-form.component.ts" region="final"> <code-pane header="hero-form/hero-form.component.ts" path="forms/src/app/hero-form/hero-form.component.ts" region="final">
</code-pane> </code-pane>
<code-pane title="hero-form/hero-form.component.html" path="forms/src/app/hero-form/hero-form.component.html" region="final"> <code-pane header="hero-form/hero-form.component.html" path="forms/src/app/hero-form/hero-form.component.html" region="final">
</code-pane> </code-pane>
<code-pane title="hero.ts" path="forms/src/app/hero.ts"> <code-pane header="hero.ts" path="forms/src/app/hero.ts">
</code-pane> </code-pane>
<code-pane title="app.module.ts" path="forms/src/app/app.module.ts"> <code-pane header="app.module.ts" path="forms/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="app.component.html" path="forms/src/app/app.component.html"> <code-pane header="app.component.html" path="forms/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane title="app.component.ts" path="forms/src/app/app.component.ts"> <code-pane header="app.component.ts" path="forms/src/app/app.component.ts">
</code-pane> </code-pane>
<code-pane title="main.ts" path="forms/src/main.ts"> <code-pane header="main.ts" path="forms/src/main.ts">
</code-pane> </code-pane>
<code-pane title="forms.css" path="forms/src/assets/forms.css"> <code-pane header="forms.css" path="forms/src/assets/forms.css">
</code-pane> </code-pane>

View File

@ -636,7 +636,7 @@ NgModules are delivered within scoped packages whose names begin with the Angula
Import a scoped package in the same way that you import a normal package. Import a scoped package in the same way that you import a normal package.
<code-example path="architecture/src/app/app.component.ts" linenums="false" title="architecture/src/app/app.component.ts (import)" region="import"> <code-example path="architecture/src/app/app.component.ts" linenums="false" header="architecture/src/app/app.component.ts (import)" region="import">
</code-example> </code-example>

View File

@ -75,7 +75,7 @@ When an injectable class provides its own service to the `root` injector, the se
The following example configures a provider for `HeroService` using the `@Injectable()` decorator on the class. The following example configures a provider for `HeroService` using the `@Injectable()` decorator on the class.
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" title="src/app/heroes/heroes.service.ts" linenums="false"> </code-example> <code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" header="src/app/heroes/heroes.service.ts" linenums="false"> </code-example>
This configuration tells Angular that the app's root injector is responsible for creating an This configuration tells Angular that the app's root injector is responsible for creating an
instance of `HeroService` by invoking its constructor, instance of `HeroService` by invoking its constructor,
@ -92,7 +92,7 @@ Instead of specifying the `root` injector, you can set `providedIn` to a specifi
For example, in the following excerpt, the `@Injectable()` decorator configures a provider For example, in the following excerpt, the `@Injectable()` decorator configures a provider
that is available in any injector that includes the `HeroModule`. that is available in any injector that includes the `HeroModule`.
<code-example path="dependency-injection/src/app/heroes/hero.service.4.ts" title="src/app/heroes/hero.service.ts" linenums="false"> </code-example> <code-example path="dependency-injection/src/app/heroes/hero.service.4.ts" header="src/app/heroes/hero.service.ts" linenums="false"> </code-example>
This is generally no different from configuring the injector of the NgModule itself, This is generally no different from configuring the injector of the NgModule itself,
except that the service is tree-shakable if the NgModule doesn't use it. except that the service is tree-shakable if the NgModule doesn't use it.
@ -117,7 +117,7 @@ Here is an example of the case where the component router configuration includes
a non-default [location strategy](guide/router#location-strategy) by listing its provider a non-default [location strategy](guide/router#location-strategy) by listing its provider
in the `providers` list of the `AppModule`. in the `providers` list of the `AppModule`.
<code-example path="dependency-injection-in-action/src/app/app.module.ts" region="providers" title="src/app/app.module.ts (providers)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/app.module.ts" region="providers" header="src/app/app.module.ts (providers)" linenums="false">
</code-example> </code-example>
@ -132,7 +132,7 @@ by configuring the provider at the component level using the `@Component` metada
The following example is a revised `HeroesComponent` that specifies `HeroService` in its `providers` array. `HeroService` can provide heroes to instances of this component, or to any child component instances. The following example is a revised `HeroesComponent` that specifies `HeroService` in its `providers` array. `HeroService` can provide heroes to instances of this component, or to any child component instances.
<code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" title="src/app/heroes/heroes.component.ts" linenums="false"> <code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts" linenums="false">
</code-example> </code-example>
### Element injectors ### Element injectors
@ -207,7 +207,7 @@ that would make the `VillainsService` available everywhere in the application, i
Instead, you can provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this: Instead, you can provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this:
<code-example path="hierarchical-dependency-injection/src/app/villains-list.component.ts" linenums="false" title="src/app/villains-list.component.ts (metadata)" region="metadata"> <code-example path="hierarchical-dependency-injection/src/app/villains-list.component.ts" linenums="false" header="src/app/villains-list.component.ts (metadata)" region="metadata">
</code-example> </code-example>
@ -250,14 +250,14 @@ It caches a single `HeroTaxReturn`, tracks changes to that return, and can save
It also delegates to the application-wide singleton `HeroService`, which it gets by injection. It also delegates to the application-wide singleton `HeroService`, which it gets by injection.
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.service.ts" title="src/app/hero-tax-return.service.ts"> <code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.service.ts" header="src/app/hero-tax-return.service.ts">
</code-example> </code-example>
Here is the `HeroTaxReturnComponent` that makes use of it. Here is the `HeroTaxReturnComponent` that makes use of it.
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" title="src/app/hero-tax-return.component.ts"> <code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" header="src/app/hero-tax-return.component.ts">
</code-example> </code-example>
@ -273,7 +273,7 @@ Every component would share the same service instance, and each component would
To prevent this, we configure the component-level injector of `HeroTaxReturnComponent` to provide the service, using the `providers` property in the component metadata. To prevent this, we configure the component-level injector of `HeroTaxReturnComponent` to provide the service, using the `providers` property in the component metadata.
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" linenums="false" title="src/app/hero-tax-return.component.ts (providers)" region="providers"> <code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" linenums="false" header="src/app/hero-tax-return.component.ts (providers)" region="providers">
</code-example> </code-example>

View File

@ -28,7 +28,7 @@ Most apps do so in the root `AppModule`.
<code-example <code-example
path="http/src/app/app.module.ts" path="http/src/app/app.module.ts"
region="sketch" region="sketch"
title="app/app.module.ts (excerpt)" linenums="false"> header="app/app.module.ts (excerpt)" linenums="false">
</code-example> </code-example>
Having imported `HttpClientModule` into the `AppModule`, you can inject the `HttpClient` Having imported `HttpClientModule` into the `AppModule`, you can inject the `HttpClient`
@ -37,7 +37,7 @@ into an application class as shown in the following `ConfigService` example.
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="proto" region="proto"
title="app/config/config.service.ts (excerpt)" linenums="false"> header="app/config/config.service.ts (excerpt)" linenums="false">
</code-example> </code-example>
## Getting JSON data ## Getting JSON data
@ -48,7 +48,7 @@ that specifies resource URLs.
<code-example <code-example
path="http/src/assets/config.json" path="http/src/assets/config.json"
title="assets/config.json" linenums="false"> header="assets/config.json" linenums="false">
</code-example> </code-example>
The `ConfigService` fetches this file with a `get()` method on `HttpClient`. The `ConfigService` fetches this file with a `get()` method on `HttpClient`.
@ -56,7 +56,7 @@ The `ConfigService` fetches this file with a `get()` method on `HttpClient`.
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfig_1" region="getConfig_1"
title="app/config/config.service.ts (getConfig v.1)" linenums="false"> header="app/config/config.service.ts (getConfig v.1)" linenums="false">
</code-example> </code-example>
A component, such as `ConfigComponent`, injects the `ConfigService` and calls A component, such as `ConfigComponent`, injects the `ConfigService` and calls
@ -65,7 +65,7 @@ the `getConfig` service method.
<code-example <code-example
path="http/src/app/config/config.component.ts" path="http/src/app/config/config.component.ts"
region="v1" region="v1"
title="app/config/config.component.ts (showConfig v.1)" linenums="false"> header="app/config/config.component.ts (showConfig v.1)" linenums="false">
</code-example> </code-example>
Because the service method returns an `Observable` of configuration data, Because the service method returns an `Observable` of configuration data,
@ -116,7 +116,7 @@ Then, specify that interface as the `HttpClient.get()` call's type parameter in
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfig_2" region="getConfig_2"
title="app/config/config.service.ts (getConfig v.2)" linenums="false"> header="app/config/config.service.ts (getConfig v.2)" linenums="false">
</code-example> </code-example>
The callback in the updated component method receives a typed data object, which is The callback in the updated component method receives a typed data object, which is
@ -125,7 +125,7 @@ easier and safer to consume:
<code-example <code-example
path="http/src/app/config/config.component.ts" path="http/src/app/config/config.component.ts"
region="v2" region="v2"
title="app/config/config.component.ts (showConfig v.2)" linenums="false"> header="app/config/config.component.ts (showConfig v.2)" linenums="false">
</code-example> </code-example>
### Reading the full response ### Reading the full response
@ -146,7 +146,7 @@ The component's `showConfigResponse()` method displays the response headers as w
<code-example <code-example
path="http/src/app/config/config.component.ts" path="http/src/app/config/config.component.ts"
region="showConfigResponse" region="showConfigResponse"
title="app/config/config.component.ts (showConfigResponse)" header="app/config/config.component.ts (showConfigResponse)"
linenums="false"> linenums="false">
</code-example> </code-example>
@ -161,7 +161,7 @@ You _could_ handle in the component by adding a second callback to the `.subscri
<code-example <code-example
path="http/src/app/config/config.component.ts" path="http/src/app/config/config.component.ts"
region="v3" region="v3"
title="app/config/config.component.ts (showConfig v.3 with error handling)" header="app/config/config.component.ts (showConfig v.3 with error handling)"
linenums="false"> linenums="false">
</code-example> </code-example>
@ -188,7 +188,7 @@ You might first devise an error handler like this one:
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="handleError" region="handleError"
title="app/config/config.service.ts (handleError)" linenums="false"> header="app/config/config.service.ts (handleError)" linenums="false">
</code-example> </code-example>
Notice that this handler returns an RxJS [`ErrorObservable`](#rxjs) with a user-friendly error message. Notice that this handler returns an RxJS [`ErrorObservable`](#rxjs) with a user-friendly error message.
@ -201,7 +201,7 @@ and _pipe them through_ to the error handler.
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfig_3" region="getConfig_3"
title="app/config/config.service.ts (getConfig v.3 with error handler)" linenums="false"> header="app/config/config.service.ts (getConfig v.3 with error handler)" linenums="false">
</code-example> </code-example>
### `retry()` ### `retry()`
@ -218,7 +218,7 @@ _Pipe_ it onto the `HttpClient` method result just before the error handler.
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfig" region="getConfig"
title="app/config/config.service.ts (getConfig with retry)" linenums="false"> header="app/config/config.service.ts (getConfig with retry)" linenums="false">
</code-example> </code-example>
{@a rxjs} {@a rxjs}
@ -239,7 +239,7 @@ If you're following along with these code snippets, note that you must import th
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="rxjs-imports" region="rxjs-imports"
title="app/config/config.service.ts (RxJS imports)" linenums="false"> header="app/config/config.service.ts (RxJS imports)" linenums="false">
</code-example> </code-example>
## Requesting non-JSON data ## Requesting non-JSON data
@ -252,7 +252,7 @@ as an `Observable<string>`.
<code-example <code-example
path="http/src/app/downloader/downloader.service.ts" path="http/src/app/downloader/downloader.service.ts"
region="getTextFile" region="getTextFile"
title="app/downloader/downloader.service.ts (getTextFile)" linenums="false"> header="app/downloader/downloader.service.ts (getTextFile)" linenums="false">
</code-example> </code-example>
`HttpClient.get()` returns a string rather than the default JSON because of the `responseType` option. `HttpClient.get()` returns a string rather than the default JSON because of the `responseType` option.
@ -264,7 +264,7 @@ A `download()` method in the `DownloaderComponent` initiates the request by subs
<code-example <code-example
path="http/src/app/downloader/downloader.component.ts" path="http/src/app/downloader/downloader.component.ts"
region="download" region="download"
title="app/downloader/downloader.component.ts (download)" linenums="false"> header="app/downloader/downloader.component.ts (download)" linenums="false">
</code-example> </code-example>
## Sending data to the server ## Sending data to the server
@ -289,7 +289,7 @@ to every `HttpClient` save method.
<code-example <code-example
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="http-options" region="http-options"
title="app/heroes/heroes.service.ts (httpOptions)" linenums="false"> header="app/heroes/heroes.service.ts (httpOptions)" linenums="false">
</code-example> </code-example>
### Making a POST request ### Making a POST request
@ -300,7 +300,7 @@ In the following example, the `HeroesService` posts when adding a hero to the da
<code-example <code-example
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="addHero" region="addHero"
title="app/heroes/heroes.service.ts (addHero)" linenums="false"> header="app/heroes/heroes.service.ts (addHero)" linenums="false">
</code-example> </code-example>
The `HttpClient.post()` method is similar to `get()` in that it has a type parameter The `HttpClient.post()` method is similar to `get()` in that it has a type parameter
@ -320,7 +320,7 @@ the `Observable` returned by this service method.
<code-example <code-example
path="http/src/app/heroes/heroes.component.ts" path="http/src/app/heroes/heroes.component.ts"
region="add-hero-subscribe" region="add-hero-subscribe"
title="app/heroes/heroes.component.ts (addHero)" linenums="false"> header="app/heroes/heroes.component.ts (addHero)" linenums="false">
</code-example> </code-example>
When the server responds successfully with the newly added hero, the component adds When the server responds successfully with the newly added hero, the component adds
@ -334,7 +334,7 @@ in the request URL.
<code-example <code-example
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="deleteHero" region="deleteHero"
title="app/heroes/heroes.service.ts (deleteHero)" linenums="false"> header="app/heroes/heroes.service.ts (deleteHero)" linenums="false">
</code-example> </code-example>
The `HeroesComponent` initiates the actual DELETE operation by subscribing to The `HeroesComponent` initiates the actual DELETE operation by subscribing to
@ -343,7 +343,7 @@ the `Observable` returned by this service method.
<code-example <code-example
path="http/src/app/heroes/heroes.component.ts" path="http/src/app/heroes/heroes.component.ts"
region="delete-hero-subscribe" region="delete-hero-subscribe"
title="app/heroes/heroes.component.ts (deleteHero)" linenums="false"> header="app/heroes/heroes.component.ts (deleteHero)" linenums="false">
</code-example> </code-example>
The component isn't expecting a result from the delete operation, so it subscribes without a callback. Even though you are not using the result, you still have to subscribe. Calling the `subscribe()` method _executes_ the observable, which is what initiates the DELETE request. The component isn't expecting a result from the delete operation, so it subscribes without a callback. Even though you are not using the result, you still have to subscribe. Calling the `subscribe()` method _executes_ the observable, which is what initiates the DELETE request.
@ -403,7 +403,7 @@ The following `HeroesService` example is just like the POST example.
<code-example <code-example
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="updateHero" region="updateHero"
title="app/heroes/heroes.service.ts (updateHero)" linenums="false"> header="app/heroes/heroes.service.ts (updateHero)" linenums="false">
</code-example> </code-example>
For the reasons [explained above](#always-subscribe), the caller (`HeroesComponent.update()` in this case) must `subscribe()` to the observable returned from the `HttpClient.put()` For the reasons [explained above](#always-subscribe), the caller (`HeroesComponent.update()` in this case) must `subscribe()` to the observable returned from the `HttpClient.put()`
@ -464,7 +464,7 @@ Here's a pertinent excerpt from the template:
<code-example <code-example
path="http/src/app/package-search/package-search.component.html" path="http/src/app/package-search/package-search.component.html"
region="search" region="search"
title="app/package-search/package-search.component.html (search)"> header="app/package-search/package-search.component.html (search)">
</code-example> </code-example>
The `(keyup)` event binding sends every keystroke to the component's `search()` method. The `(keyup)` event binding sends every keystroke to the component's `search()` method.
@ -476,7 +476,7 @@ That's easy to implement with RxJS operators, as shown in this excerpt.
<code-example <code-example
path="http/src/app/package-search/package-search.component.ts" path="http/src/app/package-search/package-search.component.ts"
region="debounce" region="debounce"
title="app/package-search/package-search.component.ts (excerpt))"> header="app/package-search/package-search.component.ts (excerpt))">
</code-example> </code-example>
The `searchText$` is the sequence of search-box values coming from the user. The `searchText$` is the sequence of search-box values coming from the user.
@ -543,7 +543,7 @@ To implement an interceptor, declare a class that implements the `intercept()` m
Here is a do-nothing _noop_ interceptor that simply passes the request through without touching it: Here is a do-nothing _noop_ interceptor that simply passes the request through without touching it:
<code-example <code-example
path="http/src/app/http-interceptors/noop-interceptor.ts" path="http/src/app/http-interceptors/noop-interceptor.ts"
title="app/http-interceptors/noop-interceptor.ts" header="app/http-interceptors/noop-interceptor.ts"
linenums="false"> linenums="false">
</code-example> </code-example>
@ -608,7 +608,7 @@ Consider creating a "barrel" file that gathers all the interceptor providers int
<code-example <code-example
path="http/src/app/http-interceptors/index.ts" path="http/src/app/http-interceptors/index.ts"
region="interceptor-providers" region="interceptor-providers"
title="app/http-interceptors/index.ts" linenums="false"> header="app/http-interceptors/index.ts" linenums="false">
</code-example> </code-example>
Then import and add it to the `AppModule` _providers array_ like this: Then import and add it to the `AppModule` _providers array_ like this:
@ -616,7 +616,7 @@ Then import and add it to the `AppModule` _providers array_ like this:
<code-example <code-example
path="http/src/app/app.module.ts" path="http/src/app/app.module.ts"
region="interceptor-providers" region="interceptor-providers"
title="app/app.module.ts (interceptor providers)" linenums="false"> header="app/app.module.ts (interceptor providers)" linenums="false">
</code-example> </code-example>
As you create new interceptors, add them to the `httpInterceptorProviders` array and As you create new interceptors, add them to the `httpInterceptorProviders` array and
@ -672,7 +672,7 @@ You can clone and modify the request in a single step as in this example.
<code-example <code-example
path="http/src/app/http-interceptors/ensure-https-interceptor.ts" path="http/src/app/http-interceptors/ensure-https-interceptor.ts"
region="excerpt" region="excerpt"
title="app/http-interceptors/ensure-https-interceptor.ts (excerpt)" linenums="false"> header="app/http-interceptors/ensure-https-interceptor.ts (excerpt)" linenums="false">
</code-example> </code-example>
The `clone()` method's hash argument allows you to mutate specific properties of the request while copying the others. The `clone()` method's hash argument allows you to mutate specific properties of the request while copying the others.
@ -692,7 +692,7 @@ If you must mutate the request body, copy it first, change the copy,
<code-example <code-example
path="http/src/app/http-interceptors/trim-name-interceptor.ts" path="http/src/app/http-interceptors/trim-name-interceptor.ts"
region="excerpt" region="excerpt"
title="app/http-interceptors/trim-name-interceptor.ts (excerpt)" linenums="false"> header="app/http-interceptors/trim-name-interceptor.ts (excerpt)" linenums="false">
</code-example> </code-example>
##### Clearing the request body ##### Clearing the request body
@ -718,7 +718,7 @@ adds an authorization header with that token to every outgoing request:
<code-example <code-example
path="http/src/app/http-interceptors/auth-interceptor.ts" path="http/src/app/http-interceptors/auth-interceptor.ts"
title="app/http-interceptors/auth-interceptor.ts"> header="app/http-interceptors/auth-interceptor.ts">
</code-example> </code-example>
The practice of cloning a request to set new headers is so common that The practice of cloning a request to set new headers is so common that
@ -747,7 +747,7 @@ with the injected `MessageService`.
<code-example <code-example
path="http/src/app/http-interceptors/logging-interceptor.ts" path="http/src/app/http-interceptors/logging-interceptor.ts"
region="excerpt" region="excerpt"
title="app/http-interceptors/logging-interceptor.ts)"> header="app/http-interceptors/logging-interceptor.ts)">
</code-example> </code-example>
The RxJS `tap` operator captures whether the request succeed or failed. The RxJS `tap` operator captures whether the request succeed or failed.
@ -768,7 +768,7 @@ The `CachingInterceptor` demonstrates this approach.
<code-example <code-example
path="http/src/app/http-interceptors/caching-interceptor.ts" path="http/src/app/http-interceptors/caching-interceptor.ts"
region="v1" region="v1"
title="app/http-interceptors/caching-interceptor.ts)" linenums="false"> header="app/http-interceptors/caching-interceptor.ts)" linenums="false">
</code-example> </code-example>
The `isCachable()` function determines if the request is cachable. The `isCachable()` function determines if the request is cachable.
@ -858,7 +858,7 @@ with the `reportProgress` option set true to enable tracking of progress events.
<code-example <code-example
path="http/src/app/uploader/uploader.service.ts" path="http/src/app/uploader/uploader.service.ts"
region="upload-request" region="upload-request"
title="app/uploader/uploader.service.ts (upload request)"> header="app/uploader/uploader.service.ts (upload request)">
</code-example> </code-example>
<div class="alert is-important"> <div class="alert is-important">
@ -873,7 +873,7 @@ returns an `Observable` of `HttpEvents`, the same events processed by intercepto
<code-example <code-example
path="http/src/app/uploader/uploader.service.ts" path="http/src/app/uploader/uploader.service.ts"
region="upload-body" region="upload-body"
title="app/uploader/uploader.service.ts (upload body)" linenums="false"> header="app/uploader/uploader.service.ts (upload body)" linenums="false">
</code-example> </code-example>
The `getEventMessage` method interprets each type of `HttpEvent` in the event stream. The `getEventMessage` method interprets each type of `HttpEvent` in the event stream.
@ -881,7 +881,7 @@ The `getEventMessage` method interprets each type of `HttpEvent` in the event st
<code-example <code-example
path="http/src/app/uploader/uploader.service.ts" path="http/src/app/uploader/uploader.service.ts"
region="getEventMessage" region="getEventMessage"
title="app/uploader/uploader.service.ts (getEventMessage)" linenums="false"> header="app/uploader/uploader.service.ts (getEventMessage)" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -964,7 +964,7 @@ along with the other symbols your tests require.
<code-example <code-example
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="imports" region="imports"
title="app/testing/http-client.spec.ts (imports)" linenums="false"> header="app/testing/http-client.spec.ts (imports)" linenums="false">
</code-example> </code-example>
Then add the `HttpClientTestingModule` to the `TestBed` and continue with Then add the `HttpClientTestingModule` to the `TestBed` and continue with
@ -973,7 +973,7 @@ the setup of the _service-under-test_.
<code-example <code-example
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="setup" region="setup"
title="app/testing/http-client.spec.ts(setup)" linenums="false"> header="app/testing/http-client.spec.ts(setup)" linenums="false">
</code-example> </code-example>
Now requests made in the course of your tests will hit the testing backend instead of the normal backend. Now requests made in the course of your tests will hit the testing backend instead of the normal backend.
@ -988,7 +988,7 @@ Now you can write a test that expects a GET Request to occur and provides a mock
<code-example <code-example
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="get-test" region="get-test"
title="app/testing/http-client.spec.ts(httpClient.get)" linenums="false"> header="app/testing/http-client.spec.ts(httpClient.get)" linenums="false">
</code-example> </code-example>
The last step, verifying that no requests remain outstanding, is common enough for you to move it into an `afterEach()` step: The last step, verifying that no requests remain outstanding, is common enough for you to move it into an `afterEach()` step:

View File

@ -57,7 +57,7 @@ To set your app's locale to another value, use the CLI parameter `--configuratio
If you use JIT, you also need to define the `LOCALE_ID` provider in your main module: If you use JIT, you also need to define the `LOCALE_ID` provider in your main module:
<code-example path="i18n/doc-files/app.module.ts" title="src/app/app.module.ts" linenums="false"> <code-example path="i18n/doc-files/app.module.ts" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
@ -97,7 +97,7 @@ The CLI imports the locale data for you when you use the parameter `--configurat
If you want to import locale data for other languages, you can do it manually: If you want to import locale data for other languages, you can do it manually:
<code-example path="i18n/doc-files/app.locale_data.ts" region="import-locale" title="src/app/app.module.ts" linenums="false"> <code-example path="i18n/doc-files/app.locale_data.ts" region="import-locale" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
The first parameter is an object containing the locale data imported from `@angular/common/locales`. The first parameter is an object containing the locale data imported from `@angular/common/locales`.
@ -112,7 +112,7 @@ The files in `@angular/common/locales` contain most of the locale data that you
need, but some advanced formatting options might only be available in the extra dataset that you can need, but some advanced formatting options might only be available in the extra dataset that you can
import from `@angular/common/locales/extra`. An error message informs you when this is the case. import from `@angular/common/locales/extra`. An error message informs you when this is the case.
<code-example path="i18n/doc-files/app.locale_data_extra.ts" region="import-locale-extra" title="src/app/app.module.ts" linenums="false"> <code-example path="i18n/doc-files/app.locale_data_extra.ts" region="import-locale-extra" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -158,12 +158,12 @@ text is to be translated.
In the example below, an `<h1>` tag displays a simple English language greeting, "Hello i18n!" In the example below, an `<h1>` tag displays a simple English language greeting, "Hello i18n!"
<code-example path="i18n/doc-files/app.component.html" region="greeting" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="greeting" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag. To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag.
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="i18n-attribute" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -183,7 +183,7 @@ To translate a text message accurately, the translator may need additional infor
You can add a description of the text message as the value of the `i18n` attribute, as shown in the You can add a description of the text message as the value of the `i18n` attribute, as shown in the
example below: example below:
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-desc" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-desc" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The translator may also need to know the meaning or intent of the text message within this particular The translator may also need to know the meaning or intent of the text message within this particular
@ -192,7 +192,7 @@ app context.
You add context by beginning the `i18n` attribute value with the _meaning_ and You add context by beginning the `i18n` attribute value with the _meaning_ and
separating it from the _description_ with the `|` character: `<meaning>|<description>` separating it from the _description_ with the `|` character: `<meaning>|<description>`
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-meaning" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-meaning" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
All occurrences of a text message that have the same meaning will have the same translation. All occurrences of a text message that have the same meaning will have the same translation.
@ -220,7 +220,7 @@ You must then update the translation file with the new id.
Alternatively, you can specify a custom id in the `i18n` attribute by using the prefix `@@`. Alternatively, you can specify a custom id in the `i18n` attribute by using the prefix `@@`.
The example below defines the custom id `introductionHeader`: The example below defines the custom id `introductionHeader`:
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-solo-id' title='app/app.component.html' linenums="false"> <code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-solo-id' header='app/app.component.html' linenums="false">
</code-example> </code-example>
When you specify a custom id, the extractor tool and compiler generate a translation unit with that When you specify a custom id, the extractor tool and compiler generate a translation unit with that
@ -238,12 +238,12 @@ You can use a custom id in combination with a description by including both in t
`i18n` attribute. In the example below, the `i18n` attribute value includes a description, followed `i18n` attribute. In the example below, the `i18n` attribute value includes a description, followed
by the custom `id`: by the custom `id`:
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-id' title='app/app.component.html' linenums="false"> <code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-id' header='app/app.component.html' linenums="false">
</code-example> </code-example>
You also can add a meaning, as shown in this example: You also can add a meaning, as shown in this example:
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-meaning-and-id' title='app/app.component.html' linenums="false"> <code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-meaning-and-id' header='app/app.component.html' linenums="false">
</code-example> </code-example>
#### Define unique custom ids #### Define unique custom ids
@ -287,7 +287,7 @@ However, if you don't want to create a new DOM element merely to facilitate tran
you can wrap the text in an `<ng-container>` element. you can wrap the text in an `<ng-container>` element.
The `<ng-container>` is transformed into an html comment: The `<ng-container>` is transformed into an html comment:
<code-example path="i18n/src/app/app.component.html" region="i18n-ng-container" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-ng-container" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
{@a translate-attributes} {@a translate-attributes}
@ -296,14 +296,14 @@ The `<ng-container>` is transformed into an html comment:
Displayed text is sometimes supplied as the value of an attribute, rather than the content of tag. Displayed text is sometimes supplied as the value of an attribute, rather than the content of tag.
For example, if your template has an image with a `title` attribute, the text value of the `title` attribute needs to be translated. For example, if your template has an image with a `title` attribute, the text value of the `title` attribute needs to be translated.
<code-example path="i18n/doc-files/app.component.html" region="i18n-title" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="i18n-title" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
To mark an attribute for translation, add an attribute in the form of `i18n-x`, To mark an attribute for translation, add an attribute in the form of `i18n-x`,
where `x` is the name of the attribute to translate. The following example shows how to mark the where `x` is the name of the attribute to translate. The following example shows how to mark the
`title` attribute for translation by adding the `i18n-title` attribute on the `img` tag: `title` attribute for translation by adding the `i18n-title` attribute on the `img` tag:
<code-example path="i18n/src/app/app.component.html" region="i18n-title-translate" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-title-translate" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
This technique works for any attribute of any element. This technique works for any attribute of any element.
@ -328,7 +328,7 @@ Other languages might express the cardinality differently.
The example below shows how to use a `plural` ICU expression to display one of those three options The example below shows how to use a `plural` ICU expression to display one of those three options
based on when the update occurred: based on when the update occurred:
<code-example path="i18n/src/app/app.component.html" region="i18n-plural" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-plural" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
* The first parameter is the key. It is bound to the component property (`minutes`), which determines * The first parameter is the key. It is bound to the component property (`minutes`), which determines
@ -384,7 +384,7 @@ The following format message in the component template binds to the component's
which outputs one of the following string values: "m", "f" or "o". which outputs one of the following string values: "m", "f" or "o".
The message maps those values to the appropriate translations: The message maps those values to the appropriate translations:
<code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-select" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
{@a nesting-ICUS} {@a nesting-ICUS}
@ -392,7 +392,7 @@ The message maps those values to the appropriate translations:
You can also nest different ICU expressions together, as shown in this example: You can also nest different ICU expressions together, as shown in this example:
<code-example path="i18n/src/app/app.component.html" region="i18n-nested" title="src/app/app.component.html"> <code-example path="i18n/src/app/app.component.html" region="i18n-nested" header="src/app/app.component.html">
</code-example> </code-example>
{@a ng-xi18n} {@a ng-xi18n}
@ -530,7 +530,7 @@ This sample file is easy to translate without a special editor or knowledge of F
1. Open `messages.fr.xlf` and find the first `<trans-unit>` section: 1. Open `messages.fr.xlf` and find the first `<trans-unit>` section:
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello-before" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> > <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello-before" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
> This XML element represents the translation of the `<h1>` greeting tag that you marked with the > This XML element represents the translation of the `<h1>` greeting tag that you marked with the
@ -546,12 +546,12 @@ This sample file is easy to translate without a special editor or knowledge of F
and context provided by the source, description, and meaning elements to guide your selection of and context provided by the source, description, and meaning elements to guide your selection of
the appropriate French translation. the appropriate French translation.
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;, after translation)" linenums="false"> > <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;, after translation)" linenums="false">
</code-example> </code-example>
3. Translate the other text nodes the same way: 3. Translate the other text nodes the same way:
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-other-nodes" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> > <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-other-nodes" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
<div class="alert is-important"> <div class="alert is-important">
@ -578,7 +578,7 @@ must be just below the translation unit for the logo.
To translate a `plural`, translate its ICU format match values: To translate a `plural`, translate its ICU format match values:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-plural" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-plural" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
You can add or remove plural cases, with each language having its own cardinality. (See You can add or remove plural cases, with each language having its own cardinality. (See
@ -589,7 +589,7 @@ You can add or remove plural cases, with each language having its own cardinalit
Below is the content of our example `select` ICU expression in the component template: Below is the content of our example `select` ICU expression in the component template:
<code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-select" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The extraction tool broke that into two translation units because ICU expressions are extracted The extraction tool broke that into two translation units because ICU expressions are extracted
@ -600,18 +600,18 @@ In place of the `select` is a placeholder, `<x id="ICU">`, that represents the `
Translate the text and move around the placeholder if necessary, but don't remove it. If you remove Translate the text and move around the placeholder if necessary, but don't remove it. If you remove
the placeholder, the ICU expression will not be present in your translated app. the placeholder, the ICU expression will not be present in your translated app.
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-1" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-1" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
The second translation unit, immediately below the first one, contains the `select` message. The second translation unit, immediately below the first one, contains the `select` message.
Translate that as well. Translate that as well.
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-2" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-2" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
Here they are together, after translation: Here they are together, after translation:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-select" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-select" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
{@a translate-nested} {@a translate-nested}
@ -620,17 +620,17 @@ Here they are together, after translation:
A nested expression is similar to the previous examples. As in the previous example, there are A nested expression is similar to the previous examples. As in the previous example, there are
two translation units. The first one contains the text outside of the nested expression: two translation units. The first one contains the text outside of the nested expression:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-1" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-1" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
The second unit contains the complete nested expression: The second unit contains the complete nested expression:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-2" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-2" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
And both together: And both together:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
The entire template translation is complete. The next section describes how to load that translation The entire template translation is complete. The next section describes how to load that translation
@ -642,15 +642,15 @@ into the app.
The sample app and its translation file are now as follows: The sample app and its translation file are now as follows:
<code-tabs> <code-tabs>
<code-pane title="src/app/app.component.html" path="i18n/src/app/app.component.html"> <code-pane header="src/app/app.component.html" path="i18n/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane title="src/app/app.component.ts" path="i18n/src/app/app.component.ts"> <code-pane header="src/app/app.component.ts" path="i18n/src/app/app.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/app.module.ts" path="i18n/src/app/app.module.ts"> <code-pane header="src/app/app.module.ts" path="i18n/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="src/main.ts" path="i18n/doc-files/main.1.ts"> <code-pane header="src/main.ts" path="i18n/doc-files/main.1.ts">
</code-pane> </code-pane>
<code-pane title="src/locale/messages.fr.xlf" path="i18n/doc-files/messages.fr.xlf.html"> <code-pane header="src/locale/messages.fr.xlf" path="i18n/doc-files/messages.fr.xlf.html">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -790,12 +790,12 @@ while compiling the app:
The Angular `bootstrapModule` method has a second `compilerOptions` parameter that can influence the The Angular `bootstrapModule` method has a second `compilerOptions` parameter that can influence the
behavior of the compiler. You can use it to specify the translation providers: behavior of the compiler. You can use it to specify the translation providers:
<code-example path="i18n/doc-files/main.2.ts" title="src/main.ts"> <code-example path="i18n/doc-files/main.2.ts" header="src/main.ts">
</code-example> </code-example>
Then provide the `LOCALE_ID` in the main module: Then provide the `LOCALE_ID` in the main module:
<code-example path="i18n/doc-files/app.module.ts" title="src/app/app.module.ts" linenums="false"> <code-example path="i18n/doc-files/app.module.ts" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
@ -826,7 +826,7 @@ If you use the JIT compiler, specify the warning level in the compiler config at
the 'MissingTranslationStrategy' property. The example below shows how to set the warning level to the 'MissingTranslationStrategy' property. The example below shows how to set the warning level to
error: error:
<code-example path="i18n/doc-files/main.3.ts" title="src/main.ts"> <code-example path="i18n/doc-files/main.3.ts" header="src/main.ts">
</code-example> </code-example>
### Build for multiple locales ### Build for multiple locales

View File

@ -98,7 +98,7 @@ placeholder markup in `app.component.html` with a custom nav
so you can easily navigate to your modules in the browser: so you can easily navigate to your modules in the browser:
<code-example path="lazy-loading-ngmodules/src/app/app.component.html" region="app-component-template" title="src/app/app.component.html" linenums="false"> <code-example path="lazy-loading-ngmodules/src/app/app.component.html" region="app-component-template" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -138,7 +138,7 @@ Each feature module acts as a doorway via the router. In the `AppRoutingModule`,
In `AppRoutingModule`, update the `routes` array with the following: In `AppRoutingModule`, update the `routes` array with the following:
<code-example path="lazy-loading-ngmodules/src/app/app-routing.module.ts" region="const-routes" title="src/app/app-routing.module.ts" linenums="false"> <code-example path="lazy-loading-ngmodules/src/app/app-routing.module.ts" region="const-routes" header="src/app/app-routing.module.ts" linenums="false">
</code-example> </code-example>
@ -150,7 +150,7 @@ The import statements stay the same. The first two paths are the routes to the `
Next, take a look at `customers.module.ts`. If youre using the CLI and following the steps outlined in this page, you dont have to do anything here. The feature module is like a connector between the `AppRoutingModule` and the feature routing module. The `AppRoutingModule` imports the feature module, `CustomersModule`, and `CustomersModule` in turn imports the `CustomersRoutingModule`. Next, take a look at `customers.module.ts`. If youre using the CLI and following the steps outlined in this page, you dont have to do anything here. The feature module is like a connector between the `AppRoutingModule` and the feature routing module. The `AppRoutingModule` imports the feature module, `CustomersModule`, and `CustomersModule` in turn imports the `CustomersRoutingModule`.
<code-example path="lazy-loading-ngmodules/src/app/customers/customers.module.ts" region="customers-module" title="src/app/customers/customers.module.ts" linenums="false"> <code-example path="lazy-loading-ngmodules/src/app/customers/customers.module.ts" region="customers-module" header="src/app/customers/customers.module.ts" linenums="false">
</code-example> </code-example>
@ -163,7 +163,7 @@ The `customers.module.ts` file imports the `CustomersRoutingModule` and `Custome
The next step is in `customers-routing.module.ts`. First, import the component at the top of the file with the other JavaScript import statements. Then, add the route to `CustomerListComponent`. The next step is in `customers-routing.module.ts`. First, import the component at the top of the file with the other JavaScript import statements. Then, add the route to `CustomerListComponent`.
<code-example path="lazy-loading-ngmodules/src/app/customers/customers-routing.module.ts" region="customers-routing-module" title="src/app/customers/customers-routing.module.ts" linenums="false"> <code-example path="lazy-loading-ngmodules/src/app/customers/customers-routing.module.ts" region="customers-routing-module" header="src/app/customers/customers-routing.module.ts" linenums="false">
</code-example> </code-example>
@ -172,7 +172,7 @@ Notice that the `path` is set to an empty string. This is because the path in `A
Repeat this last step of importing the `OrdersListComponent` and configuring the Routes array for the `orders-routing.module.ts`: Repeat this last step of importing the `OrdersListComponent` and configuring the Routes array for the `orders-routing.module.ts`:
<code-example path="lazy-loading-ngmodules/src/app/orders/orders-routing.module.ts" region="orders-routing-module-detail" title="src/app/orders/orders-routing.module.ts (excerpt)" linenums="false"> <code-example path="lazy-loading-ngmodules/src/app/orders/orders-routing.module.ts" region="orders-routing-module-detail" header="src/app/orders/orders-routing.module.ts (excerpt)" linenums="false">
</code-example> </code-example>

View File

@ -23,7 +23,7 @@ Each interface has a single hook method whose name is the interface name prefixe
For example, the `OnInit` interface has a hook method named `ngOnInit()` For example, the `OnInit` interface has a hook method named `ngOnInit()`
that Angular calls shortly after creating the component: that Angular calls shortly after creating the component:
<code-example path="lifecycle-hooks/src/app/peek-a-boo.component.ts" region="ngOnInit" title="peek-a-boo.component.ts (excerpt)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/peek-a-boo.component.ts" region="ngOnInit" header="peek-a-boo.component.ts (excerpt)" linenums="false"></code-example>
No directive or component will implement all of the lifecycle hooks. No directive or component will implement all of the lifecycle hooks.
Angular only calls a directive/component hook method *if it is defined*. Angular only calls a directive/component hook method *if it is defined*.
@ -339,13 +339,13 @@ The heroes will never know they're being watched.
The sneaky spy directive is simple, consisting almost entirely of `ngOnInit()` and `ngOnDestroy()` hooks The sneaky spy directive is simple, consisting almost entirely of `ngOnInit()` and `ngOnDestroy()` hooks
that log messages to the parent via an injected `LoggerService`. that log messages to the parent via an injected `LoggerService`.
<code-example path="lifecycle-hooks/src/app/spy.directive.ts" region="spy-directive" title="src/app/spy.directive.ts" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/spy.directive.ts" region="spy-directive" header="src/app/spy.directive.ts" linenums="false"></code-example>
You can apply the spy to any native or component element and it'll be initialized and destroyed You can apply the spy to any native or component element and it'll be initialized and destroyed
at the same time as that element. at the same time as that element.
Here it is attached to the repeated hero `<div>`: Here it is attached to the repeated hero `<div>`:
<code-example path="lifecycle-hooks/src/app/spy.component.html" region="template" title="src/app/spy.component.html" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/spy.component.html" region="template" header="src/app/spy.component.html" linenums="false"></code-example>
Each spy's birth and death marks the birth and death of the attached hero `<div>` Each spy's birth and death marks the birth and death of the attached hero `<div>`
with an entry in the *Hook Log* as seen here: with an entry in the *Hook Log* as seen here:
@ -425,7 +425,7 @@ You risk memory leaks if you neglect to do so.
Angular calls its `ngOnChanges()` method whenever it detects changes to ***input properties*** of the component (or directive). Angular calls its `ngOnChanges()` method whenever it detects changes to ***input properties*** of the component (or directive).
This example monitors the `OnChanges` hook. This example monitors the `OnChanges` hook.
<code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="ng-on-changes" title="on-changes.component.ts (excerpt)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="ng-on-changes" header="on-changes.component.ts (excerpt)" linenums="false"></code-example>
The `ngOnChanges()` method takes an object that maps each changed property name to a The `ngOnChanges()` method takes an object that maps each changed property name to a
[SimpleChange](api/core/SimpleChange) object holding the current and previous property values. [SimpleChange](api/core/SimpleChange) object holding the current and previous property values.
@ -433,11 +433,11 @@ This hook iterates over the changed properties and logs them.
The example component, `OnChangesComponent`, has two input properties: `hero` and `power`. The example component, `OnChangesComponent`, has two input properties: `hero` and `power`.
<code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="inputs" title="src/app/on-changes.component.ts" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="inputs" header="src/app/on-changes.component.ts" linenums="false"></code-example>
The host `OnChangesParentComponent` binds to them like this: The host `OnChangesParentComponent` binds to them like this:
<code-example path="lifecycle-hooks/src/app/on-changes-parent.component.html" region="on-changes" title="src/app/on-changes-parent.component.html"></code-example> <code-example path="lifecycle-hooks/src/app/on-changes-parent.component.html" region="on-changes" header="src/app/on-changes-parent.component.html"></code-example>
Here's the sample in action as the user makes changes. Here's the sample in action as the user makes changes.
@ -468,7 +468,7 @@ Use the `DoCheck` hook to detect and act upon changes that Angular doesn't catch
The *DoCheck* sample extends the *OnChanges* sample with the following `ngDoCheck()` hook: The *DoCheck* sample extends the *OnChanges* sample with the following `ngDoCheck()` hook:
<code-example path="lifecycle-hooks/src/app/do-check.component.ts" region="ng-do-check" title="DoCheckComponent (ngDoCheck)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/do-check.component.ts" region="ng-do-check" header="DoCheckComponent (ngDoCheck)" linenums="false"></code-example>
This code inspects certain _values of interest_, capturing and comparing their current state against previous values. This code inspects certain _values of interest_, capturing and comparing their current state against previous values.
It writes a special message to the log when there are no substantive changes to the `hero` or the `power` It writes a special message to the log when there are no substantive changes to the `hero` or the `power`
@ -497,25 +497,25 @@ The *AfterView* sample explores the `AfterViewInit()` and `AfterViewChecked()` h
Here's a child view that displays a hero's name in an `<input>`: Here's a child view that displays a hero's name in an `<input>`:
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="child-view" title="ChildComponent" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="child-view" header="ChildComponent" linenums="false"></code-example>
The `AfterViewComponent` displays this child view *within its template*: The `AfterViewComponent` displays this child view *within its template*:
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="template" title="AfterViewComponent (template)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="template" header="AfterViewComponent (template)" linenums="false"></code-example>
The following hooks take action based on changing values *within the child view*, The following hooks take action based on changing values *within the child view*,
which can only be reached by querying for the child view via the property decorated with which can only be reached by querying for the child view via the property decorated with
[@ViewChild](api/core/ViewChild). [@ViewChild](api/core/ViewChild).
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="hooks" title="AfterViewComponent (class excerpts)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="hooks" header="AfterViewComponent (class excerpts)" linenums="false"></code-example>
{@a wait-a-tick} {@a wait-a-tick}
### Abide by the unidirectional data flow rule ### Abide by the unidirectional data flow rule
The `doSomething()` method updates the screen when the hero name exceeds 10 characters. The `doSomething()` method updates the screen when the hero name exceeds 10 characters.
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="do-something" title="AfterViewComponent (doSomething)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="do-something" header="AfterViewComponent (doSomething)" linenums="false"></code-example>
Why does the `doSomething()` method wait a tick before updating `comment`? Why does the `doSomething()` method wait a tick before updating `comment`?
@ -559,7 +559,7 @@ Consider this variation on the [previous _AfterView_](guide/lifecycle-hooks#afte
This time, instead of including the child view within the template, it imports the content from This time, instead of including the child view within the template, it imports the content from
the `AfterContentComponent`'s parent. Here's the parent's template: the `AfterContentComponent`'s parent. Here's the parent's template:
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="parent-template" title="AfterContentParentComponent (template excerpt)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="parent-template" header="AfterContentParentComponent (template excerpt)" linenums="false"></code-example>
Notice that the `<app-child>` tag is tucked between the `<after-content>` tags. Notice that the `<app-child>` tag is tucked between the `<after-content>` tags.
Never put content between a component's element tags *unless you intend to project that content Never put content between a component's element tags *unless you intend to project that content
@ -567,7 +567,7 @@ into the component*.
Now look at the component's template: Now look at the component's template:
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="template" title="AfterContentComponent (template)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="template" header="AfterContentComponent (template)" linenums="false"></code-example>
The `<ng-content>` tag is a *placeholder* for the external content. The `<ng-content>` tag is a *placeholder* for the external content.
It tells Angular where to insert that content. It tells Angular where to insert that content.
@ -603,7 +603,7 @@ The following *AfterContent* hooks take action based on changing values in a *co
which can only be reached by querying for them via the property decorated with which can only be reached by querying for them via the property decorated with
[@ContentChild](api/core/ContentChild). [@ContentChild](api/core/ContentChild).
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="hooks" title="AfterContentComponent (class excerpts)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="hooks" header="AfterContentComponent (class excerpts)" linenums="false"></code-example>
{@a no-unidirectional-flow-worries} {@a no-unidirectional-flow-worries}

View File

@ -480,7 +480,7 @@ You can throw an error or take other remedial action.
Certain NgModules, such as `BrowserModule`, implement such a guard. Certain NgModules, such as `BrowserModule`, implement such a guard.
Here is a custom constructor for an NgModule called `CoreModule`. Here is a custom constructor for an NgModule called `CoreModule`.
<code-example path="ngmodule-faq/src/app/core/core.module.ts" region="ctor" title="src/app/core/core.module.ts (Constructor)" linenums="false"> <code-example path="ngmodule-faq/src/app/core/core.module.ts" region="ctor" header="src/app/core/core.module.ts (Constructor)" linenums="false">
</code-example> </code-example>
<hr/> <hr/>

View File

@ -59,7 +59,7 @@ You then import these modules into the root module.
The CLI generates the following basic app module when creating a new app. The CLI generates the following basic app module when creating a new app.
<code-example path="bootstrapping/src/app/app.module.ts" region="whole-ngmodule" title="src/app/app.module.ts" linenums="false"> <code-example path="bootstrapping/src/app/app.module.ts" region="whole-ngmodule" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
At the top are the import statements. The next section is where you configure the `@NgModule` by stating what components and directives belong to it (`declarations`) as well as which other modules it uses (`imports`). This page builds on [Bootstrapping](guide/bootstrapping), which covers the structure of an NgModule in detail. If you need more information on the structure of an `@NgModule`, be sure to read [Bootstrapping](guide/bootstrapping). At the top are the import statements. The next section is where you configure the `@NgModule` by stating what components and directives belong to it (`declarations`) as well as which other modules it uses (`imports`). This page builds on [Bootstrapping](guide/bootstrapping), which covers the structure of an NgModule in detail. If you need more information on the structure of an `@NgModule`, be sure to read [Bootstrapping](guide/bootstrapping).

View File

@ -16,7 +16,7 @@ A good example of usage can be found on the [EventEmitter](https://angular.io/ap
Here is the component definition: Here is the component definition:
<code-example path="observables-in-angular/src/main.ts" title="EventEmitter" region="eventemitter"></code-example> <code-example path="observables-in-angular/src/main.ts" header="EventEmitter" region="eventemitter"></code-example>
## HTTP ## HTTP
Angulars `HttpClient` returns observables from HTTP method calls. For instance, `http.get(/api)` returns an observable. This provides several advantages over promise-based HTTP APIs: Angulars `HttpClient` returns observables from HTTP method calls. For instance, `http.get(/api)` returns an observable. This provides several advantages over promise-based HTTP APIs:
@ -32,20 +32,20 @@ The [AsyncPipe](https://angular.io/api/common/AsyncPipe) subscribes to an observ
The following example binds the `time` observable to the component's view. The observable continuously updates the view with the current time. The following example binds the `time` observable to the component's view. The observable continuously updates the view with the current time.
<code-example path="observables-in-angular/src/main.ts" title="Using async pipe" region="pipe"></code-example> <code-example path="observables-in-angular/src/main.ts" header="Using async pipe" region="pipe"></code-example>
## Router ## Router
[`Router.events`](https://angular.io/api/router/Router#events) provides events as observables. You can use the `filter()` operator from RxJS to look for events of interest, and subscribe to them in order to make decisions based on the sequence of events in the navigation process. Here's an example: [`Router.events`](https://angular.io/api/router/Router#events) provides events as observables. You can use the `filter()` operator from RxJS to look for events of interest, and subscribe to them in order to make decisions based on the sequence of events in the navigation process. Here's an example:
<code-example path="observables-in-angular/src/main.ts" title="Router events" region="router"></code-example> <code-example path="observables-in-angular/src/main.ts" header="Router events" region="router"></code-example>
The [ActivatedRoute](https://angular.io/api/router/ActivatedRoute) is an injected router service that makes use of observables to get information about a route path and parameters. For example, `ActivateRoute.url` contains an observable that reports the route path or paths. Here's an example: The [ActivatedRoute](https://angular.io/api/router/ActivatedRoute) is an injected router service that makes use of observables to get information about a route path and parameters. For example, `ActivateRoute.url` contains an observable that reports the route path or paths. Here's an example:
<code-example path="observables-in-angular/src/main.ts" title="ActivatedRoute" region="activated_route"></code-example> <code-example path="observables-in-angular/src/main.ts" header="ActivatedRoute" region="activated_route"></code-example>
## Reactive forms ## Reactive forms
Reactive forms have properties that use observables to monitor form control values. The [`FormControl`](https://angular.io/api/forms/FormControl) properties `valueChanges` and `statusChanges` contain observables that raise change events. Subscribing to an observable form-control property is a way of triggering application logic within the component class. For example: Reactive forms have properties that use observables to monitor form control values. The [`FormControl`](https://angular.io/api/forms/FormControl) properties `valueChanges` and `statusChanges` contain observables that raise change events. Subscribing to an observable form-control property is a way of triggering application logic within the component class. For example:
<code-example path="observables-in-angular/src/main.ts" title="Reactive forms" region="forms"></code-example> <code-example path="observables-in-angular/src/main.ts" header="Reactive forms" region="forms"></code-example>

View File

@ -17,7 +17,7 @@ To execute the observable you have created and begin receiving notifications, yo
Here's an example that demonstrates the basic usage model by showing how an observable could be used to provide geolocation updates. Here's an example that demonstrates the basic usage model by showing how an observable could be used to provide geolocation updates.
<code-example path="observables/src/geolocation.ts" title="Observe geolocation updates"></code-example> <code-example path="observables/src/geolocation.ts" header="Observe geolocation updates"></code-example>
## Defining observers ## Defining observers
@ -49,11 +49,11 @@ Here's an example of creating and subscribing to a simple observable, with an ob
<code-example <code-example
path="observables/src/subscribing.ts" path="observables/src/subscribing.ts"
region="observer" region="observer"
title="Subscribe using observer"></code-example> header="Subscribe using observer"></code-example>
Alternatively, the `subscribe()` method can accept callback function definitions in line, for `next`, `error`, and `complete` handlers. For example, the following `subscribe()` call is the same as the one that specifies the predefined observer: Alternatively, the `subscribe()` method can accept callback function definitions in line, for `next`, `error`, and `complete` handlers. For example, the following `subscribe()` call is the same as the one that specifies the predefined observer:
<code-example path="observables/src/subscribing.ts" region="sub_fn" title="Subscribe with positional arguments"></code-example> <code-example path="observables/src/subscribing.ts" region="sub_fn" header="Subscribe with positional arguments"></code-example>
In either case, a `next` handler is required. The `error` and `complete` handlers are optional. In either case, a `next` handler is required. The `error` and `complete` handlers are optional.
@ -65,15 +65,15 @@ Use the `Observable` constructor to create an observable stream of any type. The
For example, to create an observable equivalent to the `of(1, 2, 3)` above, you could do something like this: For example, to create an observable equivalent to the `of(1, 2, 3)` above, you could do something like this:
<code-example path="observables/src/creating.ts" region="subscriber" title="Create observable with constructor"></code-example> <code-example path="observables/src/creating.ts" region="subscriber" header="Create observable with constructor"></code-example>
To take this example a little further, we can create an observable that publishes events. In this example, the subscriber function is defined inline. To take this example a little further, we can create an observable that publishes events. In this example, the subscriber function is defined inline.
<code-example path="observables/src/creating.ts" region="fromevent" title="Create with custom fromEvent function"></code-example> <code-example path="observables/src/creating.ts" region="fromevent" header="Create with custom fromEvent function"></code-example>
Now you can use this function to create an observable that publishes keydown events: Now you can use this function to create an observable that publishes keydown events:
<code-example path="observables/src/creating.ts" region="fromevent_use" title="Use custom fromEvent function"></code-example> <code-example path="observables/src/creating.ts" region="fromevent_use" header="Use custom fromEvent function"></code-example>
## Multicasting ## Multicasting
@ -87,15 +87,15 @@ When creating an observable you should determine how you want that observable to
Lets look at an example that counts from 1 to 3, with a one-second delay after each number emitted. Lets look at an example that counts from 1 to 3, with a one-second delay after each number emitted.
<code-example path="observables/src/multicasting.ts" region="delay_sequence" title="Create a delayed sequence"></code-example> <code-example path="observables/src/multicasting.ts" region="delay_sequence" header="Create a delayed sequence"></code-example>
Notice that if you subscribe twice, there will be two separate streams, each emitting values every second. It looks something like this: Notice that if you subscribe twice, there will be two separate streams, each emitting values every second. It looks something like this:
<code-example path="observables/src/multicasting.ts" region="subscribe_twice" title="Two subscriptions"></code-example> <code-example path="observables/src/multicasting.ts" region="subscribe_twice" header="Two subscriptions"></code-example>
Changing the observable to be multicasting could look something like this: Changing the observable to be multicasting could look something like this:
<code-example path="observables/src/multicasting.ts" region="multicast_sequence" title="Create a multicast subscriber"></code-example> <code-example path="observables/src/multicasting.ts" region="multicast_sequence" header="Create a multicast subscriber"></code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
Multicasting observables take a bit more setup, but they can be useful for certain applications. Later we will look at tools that simplify the process of multicasting, allowing you to take any observable and make it multicasting. Multicasting observables take a bit more setup, but they can be useful for certain applications. Later we will look at tools that simplify the process of multicasting, allowing you to take any observable and make it multicasting.

View File

@ -26,7 +26,7 @@ In this page, you'll use pipes to transform a component's birthday property into
a human-friendly date. a human-friendly date.
<code-example path="pipes/src/app/hero-birthday1.component.ts" title="src/app/hero-birthday1.component.ts" linenums="false"> <code-example path="pipes/src/app/hero-birthday1.component.ts" header="src/app/hero-birthday1.component.ts" linenums="false">
</code-example> </code-example>
@ -35,7 +35,7 @@ a human-friendly date.
Focus on the component's template. Focus on the component's template.
<code-example path="pipes/src/app/app.component.html" region="hero-birthday-template" title="src/app/app.component.html" linenums="false"> <code-example path="pipes/src/app/app.component.html" region="hero-birthday-template" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -79,7 +79,7 @@ Modify the birthday template to give the date pipe a format parameter.
After formatting the hero's April 15th birthday, it renders as **<samp>04/15/88</samp>**: After formatting the hero's April 15th birthday, it renders as **<samp>04/15/88</samp>**:
<code-example path="pipes/src/app/app.component.html" region="format-birthday" title="src/app/app.component.html" linenums="false"> <code-example path="pipes/src/app/app.component.html" region="format-birthday" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -95,7 +95,7 @@ Write a second component that *binds* the pipe's format parameter
to the component's `format` property. Here's the template for that component: to the component's `format` property. Here's the template for that component:
<code-example path="pipes/src/app/hero-birthday2.component.ts" region="template" title="src/app/hero-birthday2.component.ts (template)" linenums="false"> <code-example path="pipes/src/app/hero-birthday2.component.ts" region="template" header="src/app/hero-birthday2.component.ts (template)" linenums="false">
</code-example> </code-example>
@ -106,7 +106,7 @@ That method toggles the component's `format` property between a short form
(`'shortDate'`) and a longer form (`'fullDate'`). (`'shortDate'`) and a longer form (`'fullDate'`).
<code-example path="pipes/src/app/hero-birthday2.component.ts" region="class" title="src/app/hero-birthday2.component.ts (class)" linenums="false"> <code-example path="pipes/src/app/hero-birthday2.component.ts" region="class" header="src/app/hero-birthday2.component.ts (class)" linenums="false">
</code-example> </code-example>
@ -143,7 +143,7 @@ the birthday is chained to the `DatePipe` and on to the `UpperCasePipe`.
The birthday displays as **<samp>APR 15, 1988</samp>**. The birthday displays as **<samp>APR 15, 1988</samp>**.
<code-example path="pipes/src/app/app.component.html" region="chained-birthday" title="src/app/app.component.html" linenums="false"> <code-example path="pipes/src/app/app.component.html" region="chained-birthday" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -153,7 +153,7 @@ This example&mdash;which displays **<samp>FRIDAY, APRIL 15, 1988</samp>**&mdash;
the same pipes as above, but passes in a parameter to `date` as well. the same pipes as above, but passes in a parameter to `date` as well.
<code-example path="pipes/src/app/app.component.html" region="chained-parameter-birthday" title="src/app/app.component.html" linenums="false"> <code-example path="pipes/src/app/app.component.html" region="chained-parameter-birthday" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -166,7 +166,7 @@ You can write your own custom pipes.
Here's a custom pipe named `ExponentialStrengthPipe` that can boost a hero's powers: Here's a custom pipe named `ExponentialStrengthPipe` that can boost a hero's powers:
<code-example path="pipes/src/app/exponential-strength.pipe.ts" title="src/app/exponential-strength.pipe.ts" linenums="false"> <code-example path="pipes/src/app/exponential-strength.pipe.ts" header="src/app/exponential-strength.pipe.ts" linenums="false">
</code-example> </code-example>
@ -200,7 +200,7 @@ Technically, it's optional; Angular looks for and executes the `transform` metho
Now you need a component to demonstrate the pipe. Now you need a component to demonstrate the pipe.
<code-example path="pipes/src/app/power-booster.component.ts" title="src/app/power-booster.component.ts" linenums="false"> <code-example path="pipes/src/app/power-booster.component.ts" header="src/app/power-booster.component.ts" linenums="false">
</code-example> </code-example>
<figure> <figure>
@ -240,7 +240,7 @@ Upgrade the example to a "Power Boost Calculator" that combines
your pipe and two-way data binding with `ngModel`. your pipe and two-way data binding with `ngModel`.
<code-example path="pipes/src/app/power-boost-calculator.component.ts" title="src/app/power-boost-calculator.component.ts"> <code-example path="pipes/src/app/power-boost-calculator.component.ts" header="src/app/power-boost-calculator.component.ts">
</code-example> </code-example>
@ -270,7 +270,7 @@ In the next example, the component uses the default, aggressive change detection
its display of every hero in the `heroes` array. Here's the template: its display of every hero in the `heroes` array. Here's the template:
<code-example path="pipes/src/app/flying-heroes.component.html" region="template-1" title="src/app/flying-heroes.component.html (v1)" linenums="false"> <code-example path="pipes/src/app/flying-heroes.component.html" region="template-1" header="src/app/flying-heroes.component.html (v1)" linenums="false">
</code-example> </code-example>
@ -278,7 +278,7 @@ its display of every hero in the `heroes` array. Here's the template:
The companion component class provides heroes, adds heroes into the array, and can reset the array. The companion component class provides heroes, adds heroes into the array, and can reset the array.
<code-example path="pipes/src/app/flying-heroes.component.ts" region="v1" title="src/app/flying-heroes.component.ts (v1)" linenums="false"> <code-example path="pipes/src/app/flying-heroes.component.ts" region="v1" header="src/app/flying-heroes.component.ts (v1)" linenums="false">
</code-example> </code-example>
@ -292,7 +292,7 @@ If you added the ability to remove or change a hero, Angular would detect those
Add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroes to just those heroes who can fly. Add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroes to just those heroes who can fly.
<code-example path="pipes/src/app/flying-heroes.component.html" region="template-flying-heroes" title="src/app/flying-heroes.component.html (flyers)" linenums="false"> <code-example path="pipes/src/app/flying-heroes.component.html" region="template-flying-heroes" header="src/app/flying-heroes.component.html (flyers)" linenums="false">
</code-example> </code-example>
@ -300,7 +300,7 @@ Add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroe
Here's the `FlyingHeroesPipe` implementation, which follows the pattern for custom pipes described earlier. Here's the `FlyingHeroesPipe` implementation, which follows the pattern for custom pipes described earlier.
<code-example path="pipes/src/app/flying-heroes.pipe.ts" region="pure" title="src/app/flying-heroes.pipe.ts" linenums="false"> <code-example path="pipes/src/app/flying-heroes.pipe.ts" region="pure" header="src/app/flying-heroes.pipe.ts" linenums="false">
</code-example> </code-example>
@ -314,7 +314,7 @@ It's just using a different change-detection algorithm that ignores changes to t
Notice how a hero is added: Notice how a hero is added:
<code-example path="pipes/src/app/flying-heroes.component.ts" region="push" title="src/app/flying-heroes.component.ts" linenums="false"> <code-example path="pipes/src/app/flying-heroes.component.ts" region="push" header="src/app/flying-heroes.component.ts" linenums="false">
</code-example> </code-example>
@ -364,7 +364,7 @@ You make a pipe impure by setting its pure flag to false. You could make the `Fl
impure like this: impure like this:
<code-example path="pipes/src/app/flying-heroes.pipe.ts" region="pipe-decorator" title="src/app/flying-heroes.pipe.ts" linenums="false"> <code-example path="pipes/src/app/flying-heroes.pipe.ts" region="pipe-decorator" header="src/app/flying-heroes.pipe.ts" linenums="false">
</code-example> </code-example>
@ -422,11 +422,11 @@ The complete implementation is as follows:
<code-tabs> <code-tabs>
<code-pane title="FlyingHeroesImpurePipe" path="pipes/src/app/flying-heroes.pipe.ts" region="impure"> <code-pane header="FlyingHeroesImpurePipe" path="pipes/src/app/flying-heroes.pipe.ts" region="impure">
</code-pane> </code-pane>
<code-pane title="FlyingHeroesPipe" path="pipes/src/app/flying-heroes.pipe.ts" region="pure"> <code-pane header="FlyingHeroesPipe" path="pipes/src/app/flying-heroes.pipe.ts" region="pure">
</code-pane> </code-pane>
@ -440,7 +440,7 @@ The only difference is the `pure` flag in the pipe metadata.
This is a good candidate for an impure pipe because the `transform` function is trivial and fast. This is a good candidate for an impure pipe because the `transform` function is trivial and fast.
<code-example path="pipes/src/app/flying-heroes.pipe.ts" linenums="false" title="src/app/flying-heroes.pipe.ts (filter)" region="filter"> <code-example path="pipes/src/app/flying-heroes.pipe.ts" linenums="false" header="src/app/flying-heroes.pipe.ts (filter)" region="filter">
</code-example> </code-example>
@ -449,7 +449,7 @@ This is a good candidate for an impure pipe because the `transform` function is
You can derive a `FlyingHeroesImpureComponent` from `FlyingHeroesComponent`. You can derive a `FlyingHeroesImpureComponent` from `FlyingHeroesComponent`.
<code-example path="pipes/src/app/flying-heroes-impure.component.html" linenums="false" title="src/app/flying-heroes-impure.component.html (excerpt)" region="template-flying-heroes"> <code-example path="pipes/src/app/flying-heroes-impure.component.html" linenums="false" header="src/app/flying-heroes-impure.component.html (excerpt)" region="template-flying-heroes">
</code-example> </code-example>
@ -476,7 +476,7 @@ This next example binds an `Observable` of message strings
(`message$`) to a view with the `async` pipe. (`message$`) to a view with the `async` pipe.
<code-example path="pipes/src/app/hero-async-message.component.ts" title="src/app/hero-async-message.component.ts"> <code-example path="pipes/src/app/hero-async-message.component.ts" header="src/app/hero-async-message.component.ts">
</code-example> </code-example>
@ -499,7 +499,7 @@ In the following code, the pipe only calls the server when the request URL chang
The code uses the [Angular http](guide/http) client to retrieve data: The code uses the [Angular http](guide/http) client to retrieve data:
<code-example path="pipes/src/app/fetch-json.pipe.ts" title="src/app/fetch-json.pipe.ts"> <code-example path="pipes/src/app/fetch-json.pipe.ts" header="src/app/fetch-json.pipe.ts">
</code-example> </code-example>
@ -509,7 +509,7 @@ Now demonstrate it in a harness component whose template defines two bindings to
both requesting the heroes from the `heroes.json` file. both requesting the heroes from the `heroes.json` file.
<code-example path="pipes/src/app/hero-list.component.ts" title="src/app/hero-list.component.ts"> <code-example path="pipes/src/app/hero-list.component.ts" header="src/app/hero-list.component.ts">
</code-example> </code-example>

View File

@ -14,10 +14,10 @@ Observables can simplify the implementation of type-ahead suggestions. Typically
Writing this in full JavaScript can be quite involved. With observables, you can use a simple series of RxJS operators: Writing this in full JavaScript can be quite involved. With observables, you can use a simple series of RxJS operators:
<code-example path="practical-observable-usage/src/typeahead.ts" title="Typeahead"></code-example> <code-example path="practical-observable-usage/src/typeahead.ts" header="Typeahead"></code-example>
## Exponential backoff ## Exponential backoff
Exponential backoff is a technique in which you retry an API after failure, making the time in between retries longer after each consecutive failure, with a maximum number of retries after which the request is considered to have failed. This can be quite complex to implement with promises and other methods of tracking AJAX calls. With observables, it is very easy: Exponential backoff is a technique in which you retry an API after failure, making the time in between retries longer after each consecutive failure, with a maximum number of retries after which the request is considered to have failed. This can be quite complex to implement with promises and other methods of tracking AJAX calls. With observables, it is very easy:
<code-example path="practical-observable-usage/src/backoff.ts" title="Exponential backoff"></code-example> <code-example path="practical-observable-usage/src/backoff.ts" header="Exponential backoff"></code-example>

View File

@ -21,7 +21,7 @@ ng generate service User
This command creates the following `UserService` skeleton: This command creates the following `UserService` skeleton:
<code-example path="providers/src/app/user.service.0.ts" title="src/app/user.service.0.ts" linenums="false"> </code-example> <code-example path="providers/src/app/user.service.0.ts" header="src/app/user.service.0.ts" linenums="false"> </code-example>
You can now inject `UserService` anywhere in your application. You can now inject `UserService` anywhere in your application.
@ -38,11 +38,11 @@ You should always provide your service in the root injector unless there is a ca
It's also possible to specify that a service should be provided in a particular `@NgModule`. For example, if you don't want `UserService` to be available to applications unless they import a `UserModule` you've created, you can specify that the service should be provided in the module: It's also possible to specify that a service should be provided in a particular `@NgModule`. For example, if you don't want `UserService` to be available to applications unless they import a `UserModule` you've created, you can specify that the service should be provided in the module:
<code-example path="providers/src/app/user.service.1.ts" title="src/app/user.service.1.ts" linenums="false"> </code-example> <code-example path="providers/src/app/user.service.1.ts" header="src/app/user.service.1.ts" linenums="false"> </code-example>
The example above shows the preferred way to provide a service in a module. This method is preferred because it enables tree-shaking of the service if nothing injects it. If it's not possible to specify in the service which module should provide it, you can also declare a provider for the service within the module: The example above shows the preferred way to provide a service in a module. This method is preferred because it enables tree-shaking of the service if nothing injects it. If it's not possible to specify in the service which module should provide it, you can also declare a provider for the service within the module:
<code-example path="providers/src/app/user.module.ts" title="src/app/user.module.ts" linenums="false"> </code-example> <code-example path="providers/src/app/user.module.ts" header="src/app/user.module.ts" linenums="false"> </code-example>
## Limiting provider scope by lazy loading modules ## Limiting provider scope by lazy loading modules
@ -67,7 +67,7 @@ method is helpful for when you want to eagerly load a module that needs a servic
Providing a service in the component limits the service only to that component (other components in Providing a service in the component limits the service only to that component (other components in
the same module cant access it.) the same module cant access it.)
<code-example path="providers/src/app/app.component.ts" region="component-providers" title="src/app/app.component.ts" linenums="false"> <code-example path="providers/src/app/app.component.ts" region="component-providers" header="src/app/app.component.ts" linenums="false">
</code-example> </code-example>

View File

@ -126,13 +126,13 @@ As part of the initial app, the CLI created the first Angular component for you.
2. Change the `title` property from `'my-app'` to `'My First Angular App'`. 2. Change the `title` property from `'my-app'` to `'My First Angular App'`.
<code-example path="cli-quickstart/src/app/app.component.ts" region="component" title="src/app/app.component.ts" linenums="false"></code-example> <code-example path="cli-quickstart/src/app/app.component.ts" region="component" header="src/app/app.component.ts" linenums="false"></code-example>
The browser reloads automatically with the revised title. That's nice, but it could look better. The browser reloads automatically with the revised title. That's nice, but it could look better.
3. Open `./src/app/app.component.css` and give the component some style. 3. Open `./src/app/app.component.css` and give the component some style.
<code-example path="cli-quickstart/src/app/app.component.css" title="src/app/app.component.css" linenums="false"></code-example> <code-example path="cli-quickstart/src/app/app.component.css" header="src/app/app.component.css" linenums="false"></code-example>
Looking good! Looking good!

View File

@ -26,7 +26,7 @@ This section describes how to add a single form control. In the example, the use
To use reactive forms, import `ReactiveFormsModule` from the `@angular/forms` package and add it to your NgModule's `imports` array. To use reactive forms, import `ReactiveFormsModule` from the `@angular/forms` package and add it to your NgModule's `imports` array.
<code-example path="reactive-forms/src/app/app.module.ts" region="imports" title="src/app/app.module.ts (excerpt)"> <code-example path="reactive-forms/src/app/app.module.ts" region="imports" header="src/app/app.module.ts (excerpt)">
</code-example> </code-example>
@ -42,7 +42,7 @@ Generate a component for the control.
The `FormControl` class is the basic building block when using reactive forms. To register a single form control, import the `FormControl` class into your component and create a new instance of the form control to save as a class property. The `FormControl` class is the basic building block when using reactive forms. To register a single form control, import the `FormControl` class into your component and create a new instance of the form control to save as a class property.
<code-example path="reactive-forms/src/app/name-editor/name-editor.component.ts" region="create-control" title="src/app/name-editor/name-editor.component.ts"> <code-example path="reactive-forms/src/app/name-editor/name-editor.component.ts" region="create-control" header="src/app/name-editor/name-editor.component.ts">
</code-example> </code-example>
@ -52,7 +52,7 @@ Use the constructor of `FormControl` to set its initial value, which in this cas
After you create the control in the component class, you must associate it with a form control element in the template. Update the template with the form control using the `formControl` binding provided by `FormControlDirective` included in `ReactiveFormsModule`. After you create the control in the component class, you must associate it with a form control element in the template. Update the template with the form control using the `formControl` binding provided by `FormControlDirective` included in `ReactiveFormsModule`.
<code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="control-binding" linenums="false" title="src/app/name-editor/name-editor.component.html"> <code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="control-binding" linenums="false" header="src/app/name-editor/name-editor.component.html">
</code-example> </code-example>
@ -68,7 +68,7 @@ Using the template binding syntax, the form control is now registered to the `na
The form control assigned to `name` is displayed when the component is added to a template. The form control assigned to `name` is displayed when the component is added to a template.
<code-example path="reactive-forms/src/app/app.component.1.html" region="app-name-editor" linenums="false" title="src/app/app.component.html (name editor)"> <code-example path="reactive-forms/src/app/app.component.1.html" region="app-name-editor" linenums="false" header="src/app/app.component.html (name editor)">
</code-example> </code-example>
@ -92,7 +92,7 @@ You can display the value in these ways:
The following example shows you how to display the current value using interpolation in the template. The following example shows you how to display the current value using interpolation in the template.
<code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="display-value" linenums="false" title="src/app/name-editor/name-editor.component.html (control value)"> <code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="display-value" linenums="false" header="src/app/name-editor/name-editor.component.html (control value)">
</code-example> </code-example>
@ -108,13 +108,13 @@ Reactive forms have methods to change a control's value programmatically, which
The following example adds a method to the component class to update the value of the control to *Nancy* using the `setValue()` method. The following example adds a method to the component class to update the value of the control to *Nancy* using the `setValue()` method.
<code-example path="reactive-forms/src/app/name-editor/name-editor.component.ts" region="update-value" title="src/app/name-editor/name-editor.component.ts (update value)"> <code-example path="reactive-forms/src/app/name-editor/name-editor.component.ts" region="update-value" header="src/app/name-editor/name-editor.component.ts (update value)">
</code-example> </code-example>
Update the template with a button to simulate a name update. When you click the **Update Name** button, the value entered in the form control element is reflected as its current value. Update the template with a button to simulate a name update. When you click the **Update Name** button, the value entered in the form control element is reflected as its current value.
<code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="update-value" linenums="false" title="src/app/name-editor/name-editor.component.html (update value)"> <code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="update-value" linenums="false" header="src/app/name-editor/name-editor.component.html (update value)">
</code-example> </code-example>
@ -142,7 +142,7 @@ Generate a `ProfileEditor` component and import the `FormGroup` and `FormControl
</code-example> </code-example>
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="imports" title="src/app/profile-editor/profile-editor.component.ts (imports)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="imports" header="src/app/profile-editor/profile-editor.component.ts (imports)">
</code-example> </code-example>
@ -152,7 +152,7 @@ Create a property in the component class named `profileForm` and set the propert
For the profile form, add two form control instances with the names `firstName` and `lastName`. For the profile form, add two form control instances with the names `firstName` and `lastName`.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="formgroup" title="src/app/profile-editor/profile-editor.component.ts (form group)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="formgroup" header="src/app/profile-editor/profile-editor.component.ts (form group)">
</code-example> </code-example>
@ -162,7 +162,7 @@ The individual form controls are now collected within a group. A `FormGroup` ins
A form group tracks the status and changes for each of its controls, so if one of the controls changes, the parent control also emits a new status or value change. The model for the group is maintained from its members. After you define the model, you must update the template to reflect the model in the view. A form group tracks the status and changes for each of its controls, so if one of the controls changes, the parent control also emits a new status or value change. The model for the group is maintained from its members. After you define the model, you must update the template to reflect the model in the view.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="formgroup" linenums="false" title="src/app/profile-editor/profile-editor.component.html (template form group)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="formgroup" linenums="false" header="src/app/profile-editor/profile-editor.component.html (template form group)">
</code-example> </code-example>
@ -174,13 +174,13 @@ The `ProfileEditor` component accepts input from the user, but in a real scenari
Add an `ngSubmit` event listener to the `form` tag with the `onSubmit()` callback method. Add an `ngSubmit` event listener to the `form` tag with the `onSubmit()` callback method.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="ng-submit" linenums="false" title="src/app/profile-editor/profile-editor.component.html (submit event)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="ng-submit" linenums="false" header="src/app/profile-editor/profile-editor.component.html (submit event)">
</code-example> </code-example>
The `onSubmit()` method in the `ProfileEditor` component captures the current value of `profileForm`. Use `EventEmitter` to keep the form encapsulated and to provide the form value outside the component. The following example uses `console.warn` to log a message to the browser console. The `onSubmit()` method in the `ProfileEditor` component captures the current value of `profileForm`. Use `EventEmitter` to keep the form encapsulated and to provide the form value outside the component. The following example uses `console.warn` to log a message to the browser console.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="on-submit" title="src/app/profile-editor/profile-editor.component.ts (submit method)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="on-submit" header="src/app/profile-editor/profile-editor.component.ts (submit method)">
</code-example> </code-example>
@ -188,7 +188,7 @@ The `submit` event is emitted by the `form` tag using the native DOM event. You
Use a `button` element to add a button to the bottom of the form to trigger the form submission. Use a `button` element to add a button to the bottom of the form to trigger the form submission.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="submit-button" linenums="false" title="src/app/profile-editor/profile-editor.component.html (submit button)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="submit-button" linenums="false" header="src/app/profile-editor/profile-editor.component.html (submit button)">
</code-example> </code-example>
@ -202,7 +202,7 @@ Use a `button` element to add a button to the bottom of the form to trigger the
To display the `ProfileEditor` component that contains the form, add it to a component template. To display the `ProfileEditor` component that contains the form, add it to a component template.
<code-example path="reactive-forms/src/app/app.component.1.html" region="app-profile-editor" linenums="false" title="src/app/app.component.html (profile editor)"> <code-example path="reactive-forms/src/app/app.component.1.html" region="app-profile-editor" linenums="false" header="src/app/app.component.html (profile editor)">
</code-example> </code-example>
@ -220,7 +220,7 @@ When building complex forms, managing the different areas of information is easi
An address is a good example of information that can be grouped together. Form groups can accept both form control and form group instances as children. This makes composing complex form models easier to maintain and logically group together. To create a nested group in `profileForm`, add a nested `address` element to the form group instance. An address is a good example of information that can be grouped together. Form groups can accept both form control and form group instances as children. This makes composing complex form models easier to maintain and logically group together. To create a nested group in `profileForm`, add a nested `address` element to the form group instance.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="nested-formgroup" linenums="false" title="src/app/profile-editor/profile-editor.component.ts (nested form group)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="nested-formgroup" linenums="false" header="src/app/profile-editor/profile-editor.component.ts (nested form group)">
</code-example> </code-example>
@ -232,7 +232,7 @@ After you update the model in the component class, update the template to connec
Add the `address` form group containing the `firstName` and `lastName` fields to the `ProfileEditor` template. Add the `address` form group containing the `firstName` and `lastName` fields to the `ProfileEditor` template.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="formgroupname" linenums="false" title="src/app/profile-editor/profile-editor.component.html (template nested form group)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="formgroupname" linenums="false" header="src/app/profile-editor/profile-editor.component.html (template nested form group)">
</code-example> </code-example>
@ -264,13 +264,13 @@ The strict checks of the `setValue()` method help catch nesting errors in comple
In `ProfileEditorComponent`, use the `updateProfile` method with the example below to update the first name and street address for the user. In `ProfileEditorComponent`, use the `updateProfile` method with the example below to update the first name and street address for the user.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="patch-value" title="src/app/profile-editor/profile-editor.component.ts (patch value)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="patch-value" header="src/app/profile-editor/profile-editor.component.ts (patch value)">
</code-example> </code-example>
Simulate an update by adding a button to the template to update the user profile on demand. Simulate an update by adding a button to the template to update the user profile on demand.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="patch-value" linenums="false" title="src/app/profile-editor/profile-editor.component.html (update value)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="patch-value" linenums="false" header="src/app/profile-editor/profile-editor.component.html (update value)">
</code-example> </code-example>
@ -286,7 +286,7 @@ The following section refactors the `ProfileEditor` component to use the form bu
Import the `FormBuilder` class from the `@angular/forms` package. Import the `FormBuilder` class from the `@angular/forms` package.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="form-builder-imports" title="src/app/profile-editor/profile-editor.component.ts (import)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="form-builder-imports" header="src/app/profile-editor/profile-editor.component.ts (import)">
</code-example> </code-example>
@ -294,7 +294,7 @@ Import the `FormBuilder` class from the `@angular/forms` package.
The `FormBuilder` service is an injectable provider that is provided with the reactive forms module. Inject this dependency by adding it to the component constructor. The `FormBuilder` service is an injectable provider that is provided with the reactive forms module. Inject this dependency by adding it to the component constructor.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="inject-form-builder" title="src/app/profile-editor/profile-editor.component.ts (constructor)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="inject-form-builder" header="src/app/profile-editor/profile-editor.component.ts (constructor)">
</code-example> </code-example>
@ -304,7 +304,7 @@ The `FormBuilder` service has three methods: `control()`, `group()`, and `array(
Use the `group` method to create the `profileForm` controls. Use the `group` method to create the `profileForm` controls.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="form-builder" title="src/app/profile-editor/profile-editor.component.ts (form builder)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="form-builder" header="src/app/profile-editor/profile-editor.component.ts (form builder)">
</code-example> </code-example>
@ -320,11 +320,11 @@ Compare using the form builder to creating the instances manually.
<code-tabs> <code-tabs>
<code-pane path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="formgroup-compare" title="src/app/profile-editor/profile-editor.component.ts (instances)"> <code-pane path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="formgroup-compare" header="src/app/profile-editor/profile-editor.component.ts (instances)">
</code-pane> </code-pane>
<code-pane path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="formgroup-compare" title="src/app/profile-editor/profile-editor.component.ts (form builder)"> <code-pane path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="formgroup-compare" header="src/app/profile-editor/profile-editor.component.ts (form builder)">
</code-pane> </code-pane>
@ -340,7 +340,7 @@ Reactive forms include a set of validator functions for common use cases. These
Import the `Validators` class from the `@angular/forms` package. Import the `Validators` class from the `@angular/forms` package.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="validator-imports" title="src/app/profile-editor/profile-editor.component.ts (import)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="validator-imports" header="src/app/profile-editor/profile-editor.component.ts (import)">
</code-example> </code-example>
@ -350,13 +350,13 @@ The most common validation is making a field required. This section describes ho
In the `ProfileEditor` component, add the `Validators.required` static method as the second item in the array for the `firstName` control. In the `ProfileEditor` component, add the `Validators.required` static method as the second item in the array for the `firstName` control.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="required-validator" title="src/app/profile-editor/profile-editor.component.ts (required validator)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="required-validator" header="src/app/profile-editor/profile-editor.component.ts (required validator)">
</code-example> </code-example>
HTML5 has a set of built-in attributes that you can use for native validation, including `required`, `minlength`, and `maxlength`. You can take advantage of these optional attributes on your form input elements. Add the `required` attribute to the `firstName` input element. HTML5 has a set of built-in attributes that you can use for native validation, including `required`, `minlength`, and `maxlength`. You can take advantage of these optional attributes on your form input elements. Add the `required` attribute to the `firstName` input element.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="required-attribute" linenums="false" title="src/app/profile-editor/profile-editor.component.html (required attribute)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="required-attribute" linenums="false" header="src/app/profile-editor/profile-editor.component.html (required attribute)">
</code-example> </code-example>
@ -372,7 +372,7 @@ When you add a required field to the form control, its initial status is invalid
Display the current status of `profileForm` using interpolation. Display the current status of `profileForm` using interpolation.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="display-status" linenums="false" title="src/app/profile-editor/profile-editor.component.html (display status)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="display-status" linenums="false" header="src/app/profile-editor/profile-editor.component.html (display status)">
</code-example> </code-example>
@ -392,7 +392,7 @@ For more on form validation, visit the [Form Validation](guide/form-validation)
Import the `FormArray` class from `@angular/forms` to use for type information. The `FormBuilder` service is ready to create a `FormArray` instance. Import the `FormArray` class from `@angular/forms` to use for type information. The `FormBuilder` service is ready to create a `FormArray` instance.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="form-array-imports" title="src/app/profile-editor/profile-editor.component.ts (import)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="form-array-imports" header="src/app/profile-editor/profile-editor.component.ts (import)">
</code-example> </code-example>
@ -402,7 +402,7 @@ You can initialize a form array with any number of controls, from zero to many,
Use the `FormBuilder.array()` method to define the array, and the `FormBuilder.control()` method to populate the array with an initial control. Use the `FormBuilder.array()` method to define the array, and the `FormBuilder.control()` method to populate the array with an initial control.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="aliases" title="src/app/profile-editor/profile-editor.component.ts (aliases form array)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="aliases" header="src/app/profile-editor/profile-editor.component.ts (aliases form array)">
</code-example> </code-example>
@ -414,7 +414,7 @@ A getter provides easy access to the aliases in the form array instance compared
Use the getter syntax to create an `aliases` class property to retrieve the alias's form array control from the parent form group. Use the getter syntax to create an `aliases` class property to retrieve the alias's form array control from the parent form group.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="aliases-getter" title="src/app/profile-editor/profile-editor.component.ts (aliases getter)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="aliases-getter" header="src/app/profile-editor/profile-editor.component.ts (aliases getter)">
</code-example> </code-example>
@ -426,7 +426,7 @@ Use the getter syntax to create an `aliases` class property to retrieve the alia
Define a method to dynamically insert an alias control into the alias's form array. The `FormArray.push()` method inserts the control as a new item in the array. Define a method to dynamically insert an alias control into the alias's form array. The `FormArray.push()` method inserts the control as a new item in the array.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="add-alias" title="src/app/profile-editor/profile-editor.component.ts (add alias)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="add-alias" header="src/app/profile-editor/profile-editor.component.ts (add alias)">
</code-example> </code-example>
@ -438,7 +438,7 @@ To attach the aliases from your form model, you must add it to the template. Sim
Add the template HTML below after the `<div>` closing the `formGroupName` element. Add the template HTML below after the `<div>` closing the `formGroupName` element.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="formarrayname" linenums="false" title="src/app/profile-editor/profile-editor.component.html (aliases form array template)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="formarrayname" linenums="false" header="src/app/profile-editor/profile-editor.component.html (aliases form array template)">
</code-example> </code-example>

View File

@ -15,7 +15,7 @@ The [AnimationOptions](https://angular.io/api/animations/AnimationOptions) inter
To create a reusable animation, use the [`animation()`](https://angular.io/api/animations/animation) method to define an animation in a separate `.ts` file and declare this animation definition as a `const` export variable. You can then import and reuse this animation in any of your app components using the [`useAnimation()`](https://angular.io/api/animations/useAnimation) API. To create a reusable animation, use the [`animation()`](https://angular.io/api/animations/animation) method to define an animation in a separate `.ts` file and declare this animation definition as a `const` export variable. You can then import and reuse this animation in any of your app components using the [`useAnimation()`](https://angular.io/api/animations/useAnimation) API.
<code-example path="animations/src/app/animations.ts" title="src/app/animations.ts" region="reusable" language="typescript" linenums="false"> <code-example path="animations/src/app/animations.ts" header="src/app/animations.ts" region="reusable" language="typescript" linenums="false">
</code-example> </code-example>
In the above code snippet, `transAnimation` is made reusable by declaring it as an export variable. In the above code snippet, `transAnimation` is made reusable by declaring it as an export variable.
@ -27,7 +27,7 @@ In the above code snippet, `transAnimation` is made reusable by declaring it as
You can import the reusable `transAnimation` variable in your component class and reuse it using the `useAnimation()` method as shown below. You can import the reusable `transAnimation` variable in your component class and reuse it using the `useAnimation()` method as shown below.
<code-example path="animations/src/app/open-close.component.3.ts" title="src/app/open-close.component.ts" region="reusable" language="typescript" linenums="false"> <code-example path="animations/src/app/open-close.component.3.ts" header="src/app/open-close.component.ts" region="reusable" language="typescript" linenums="false">
</code-example> </code-example>
## More on Angular animations ## More on Angular animations

View File

@ -43,7 +43,7 @@ Use the `RouterModule.forRoot` method to define a set of routes. Also, import th
The following configuration defines the possible routes for the application. The following configuration defines the possible routes for the application.
<code-example path="animations/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts" region="route-animation-data" language="typescript"> <code-example path="animations/src/app/app.module.ts" linenums="false" header="src/app/app.module.ts" region="route-animation-data" language="typescript">
</code-example> </code-example>
The `home` and `about` paths are associated with the `HomeComponent` and `AboutComponent` views. The route configuration tells the Angular router to instantiate the `HomeComponent` and `AboutComponent` views when the navigation matches the corresponding path. The `home` and `about` paths are associated with the `HomeComponent` and `AboutComponent` views. The route configuration tells the Angular router to instantiate the `HomeComponent` and `AboutComponent` views when the navigation matches the corresponding path.
@ -62,12 +62,12 @@ After configuring the routes, tell the Angular router where to render the views
The `<router-outlet>` container has an attribute directive that contains data about active routes and their states, based on the `data` property that we set in the route configuration. The `<router-outlet>` container has an attribute directive that contains data about active routes and their states, based on the `data` property that we set in the route configuration.
<code-example path="animations/src/app/app.component.html" title="src/app/app.component.html" region="route-animations-outlet"> <code-example path="animations/src/app/app.component.html" header="src/app/app.component.html" region="route-animations-outlet">
</code-example> </code-example>
`AppComponent` defines a method that can detect when a view changes. The method assigns an animation state value to the animation trigger (`@routeAnimation`) based on the route configuration `data` property value. Here's an example of an `AppComponent` method that detects when a route change happens. `AppComponent` defines a method that can detect when a view changes. The method assigns an animation state value to the animation trigger (`@routeAnimation`) based on the route configuration `data` property value. Here's an example of an `AppComponent` method that detects when a route change happens.
<code-example path="animations/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts" region="prepare-router-outlet" language="typescript"> <code-example path="animations/src/app/app.component.ts" linenums="false" header="src/app/app.component.ts" region="prepare-router-outlet" language="typescript">
</code-example> </code-example>
Here, the `prepareRoute()` method takes the value of the output directive (established through `#outlet="outlet"`) and returns a string value representing the state of the animation based on the custom data of the current active route. You can use this data to control which transition to execute for each route. Here, the `prepareRoute()` method takes the value of the output directive (established through `#outlet="outlet"`) and returns a string value representing the state of the animation based on the custom data of the current active route. You can use this data to control which transition to execute for each route.
@ -79,7 +79,7 @@ Animations can be defined directly inside your components. For this example we a
The following code snippet defines a reusable animation named `slideInAnimation`. The following code snippet defines a reusable animation named `slideInAnimation`.
<code-example path="animations/src/app/animations.ts" linenums="false" title="src/app/animations.ts" region="route-animations" language="typescript"> <code-example path="animations/src/app/animations.ts" linenums="false" header="src/app/animations.ts" region="route-animations" language="typescript">
</code-example> </code-example>
The animation definition does several things: The animation definition does several things:
@ -97,14 +97,14 @@ A route change activates the animation trigger, and a transition matching the st
Make the animation definition available in your application by adding the reusable animation (`slideInAnimation`) to the `animations` metadata of the `AppComponent`. Make the animation definition available in your application by adding the reusable animation (`slideInAnimation`) to the `animations` metadata of the `AppComponent`.
<code-example path="animations/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts" region="define" language="typescript"> <code-example path="animations/src/app/app.component.ts" linenums="false" header="src/app/app.component.ts" region="define" language="typescript">
</code-example> </code-example>
### Styling the host and child components ### Styling the host and child components
During a transition, a new view is inserted directly after the old one and both elements appear on screen at the same time. To prevent this, apply additional styling to the host view, and to the removed and inserted child views. The host view must use relative positioning, and the child views must use absolute positioning. Adding styling to the views animates the containers in place, without the DOM moving things around. During a transition, a new view is inserted directly after the old one and both elements appear on screen at the same time. To prevent this, apply additional styling to the host view, and to the removed and inserted child views. The host view must use relative positioning, and the child views must use absolute positioning. Adding styling to the views animates the containers in place, without the DOM moving things around.
<code-example path="animations/src/app/animations.ts" linenums="false" title="src/app/animations.ts" region="style-view" language="typescript"> <code-example path="animations/src/app/animations.ts" linenums="false" header="src/app/animations.ts" region="style-view" language="typescript">
</code-example> </code-example>
### Querying the view containers ### Querying the view containers
@ -113,7 +113,7 @@ Use the `query()` method to find and animate elements within the current host co
Let's assume that we are routing from the *Home => About*. Let's assume that we are routing from the *Home => About*.
<code-example path="animations/src/app/animations.ts" linenums="false" title="src/app/animations.ts" region="query" language="typescript" linenums="false"> <code-example path="animations/src/app/animations.ts" linenums="false" header="src/app/animations.ts" region="query" language="typescript" linenums="false">
</code-example> </code-example>
The animation code does the following after styling the views: The animation code does the following after styling the views:

File diff suppressed because it is too large Load Diff

View File

@ -15,13 +15,13 @@ RxJS provides an implementation of the `Observable` type, which is needed until
RxJS offers a number of functions that can be used to create new observables. These functions can simplify the process of creating observables from things such as events, timers, promises, and so on. For example: RxJS offers a number of functions that can be used to create new observables. These functions can simplify the process of creating observables from things such as events, timers, promises, and so on. For example:
<code-example path="rx-library/src/simple-creation.ts" region="promise" title="Create an observable from a promise"></code-example> <code-example path="rx-library/src/simple-creation.ts" region="promise" header="Create an observable from a promise"></code-example>
<code-example path="rx-library/src/simple-creation.ts" region="interval" title="Create an observable from a counter"></code-example> <code-example path="rx-library/src/simple-creation.ts" region="interval" header="Create an observable from a counter"></code-example>
<code-example path="rx-library/src/simple-creation.ts" region="event" title="Create an observable from an event"></code-example> <code-example path="rx-library/src/simple-creation.ts" region="event" header="Create an observable from an event"></code-example>
<code-example path="rx-library/src/simple-creation.ts" region="ajax" title="Create an observable that creates an AJAX request"></code-example> <code-example path="rx-library/src/simple-creation.ts" region="ajax" header="Create an observable that creates an AJAX request"></code-example>
## Operators ## Operators
@ -29,7 +29,7 @@ Operators are functions that build on the observables foundation to enable sophi
Operators take configuration options, and they return a function that takes a source observable. When executing this returned function, the operator observes the source observables emitted values, transforms them, and returns a new observable of those transformed values. Here is a simple example: Operators take configuration options, and they return a function that takes a source observable. When executing this returned function, the operator observes the source observables emitted values, transforms them, and returns a new observable of those transformed values. Here is a simple example:
<code-example path="rx-library/src/operators.ts" title="Map operator"></code-example> <code-example path="rx-library/src/operators.ts" header="Map operator"></code-example>
You can use _pipes_ to link operators together. Pipes let you combine multiple functions into a single function. The `pipe()` function takes as its arguments the functions you want to combine, and returns a new function that, when executed, runs the composed functions in sequence. You can use _pipes_ to link operators together. Pipes let you combine multiple functions into a single function. The `pipe()` function takes as its arguments the functions you want to combine, and returns a new function that, when executed, runs the composed functions in sequence.
@ -37,11 +37,11 @@ A set of operators applied to an observable is a recipe&mdash;that is, a set of
Heres an example: Heres an example:
<code-example path="rx-library/src/operators.1.ts" title="Standalone pipe function"></code-example> <code-example path="rx-library/src/operators.1.ts" header="Standalone pipe function"></code-example>
The `pipe()` function is also a method on the RxJS `Observable`, so you use this shorter form to define the same operation: The `pipe()` function is also a method on the RxJS `Observable`, so you use this shorter form to define the same operation:
<code-example path="rx-library/src/operators.2.ts" title="Observable.pipe function"></code-example> <code-example path="rx-library/src/operators.2.ts" header="Observable.pipe function"></code-example>
### Common operators ### Common operators
@ -68,7 +68,7 @@ For instance, suppose you have an observable that makes an API request and maps
Here's an example of using the `catchError` operator to do this: Here's an example of using the `catchError` operator to do this:
<code-example path="rx-library/src/error-handling.ts" title="catchError operator"></code-example> <code-example path="rx-library/src/error-handling.ts" header="catchError operator"></code-example>
### Retry failed observable ### Retry failed observable
@ -78,7 +78,7 @@ Use the `retry` operator before the `catchError` operator. It resubscribes to th
The following converts the previous example to retry the request before catching the error: The following converts the previous example to retry the request before catching the error:
<code-example path="rx-library/src/retry-on-error.ts" title="retry operator"></code-example> <code-example path="rx-library/src/retry-on-error.ts" header="retry operator"></code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -94,4 +94,4 @@ This can be useful when scanning through code and looking for observable values.
For example: For example:
<code-example path="rx-library/src/naming-convention.ts" title="Naming observables"></code-example> <code-example path="rx-library/src/naming-convention.ts" header="Naming observables"></code-example>

View File

@ -98,7 +98,7 @@ The following template binds the value of `htmlSnippet`, once by interpolating i
content, and once by binding it to the `innerHTML` property of an element: content, and once by binding it to the `innerHTML` property of an element:
<code-example path="security/src/app/inner-html-binding.component.html" title="src/app/inner-html-binding.component.html"> <code-example path="security/src/app/inner-html-binding.component.html" header="src/app/inner-html-binding.component.html">
</code-example> </code-example>
@ -112,7 +112,7 @@ a value that an attacker might control into `innerHTML` normally causes an XSS
vulnerability. For example, code contained in a `<script>` tag is executed: vulnerability. For example, code contained in a `<script>` tag is executed:
<code-example path="security/src/app/inner-html-binding.component.ts" linenums="false" title="src/app/inner-html-binding.component.ts (class)" region="class"> <code-example path="security/src/app/inner-html-binding.component.ts" linenums="false" header="src/app/inner-html-binding.component.ts (class)" region="class">
</code-example> </code-example>
@ -200,7 +200,7 @@ your intended use of the value. Imagine that the following template needs to bin
`javascript:alert(...)` call: `javascript:alert(...)` call:
<code-example path="security/src/app/bypass-security.component.html" linenums="false" title="src/app/bypass-security.component.html (URL)" region="URL"> <code-example path="security/src/app/bypass-security.component.html" linenums="false" header="src/app/bypass-security.component.html (URL)" region="URL">
</code-example> </code-example>
@ -211,7 +211,7 @@ in development mode, logs this action to the console. To prevent
this, mark the URL value as a trusted URL using the `bypassSecurityTrustUrl` call: this, mark the URL value as a trusted URL using the `bypassSecurityTrustUrl` call:
<code-example path="security/src/app/bypass-security.component.ts" linenums="false" title="src/app/bypass-security.component.ts (trust-url)" region="trust-url"> <code-example path="security/src/app/bypass-security.component.ts" linenums="false" header="src/app/bypass-security.component.ts (trust-url)" region="trust-url">
</code-example> </code-example>
@ -231,13 +231,13 @@ could execute. So call a method on the controller to construct a trusted video U
Angular to allow binding into `<iframe src>`: Angular to allow binding into `<iframe src>`:
<code-example path="security/src/app/bypass-security.component.html" linenums="false" title="src/app/bypass-security.component.html (iframe)" region="iframe"> <code-example path="security/src/app/bypass-security.component.html" linenums="false" header="src/app/bypass-security.component.html (iframe)" region="iframe">
</code-example> </code-example>
<code-example path="security/src/app/bypass-security.component.ts" linenums="false" title="src/app/bypass-security.component.ts (trust-video-url)" region="trust-video-url"> <code-example path="security/src/app/bypass-security.component.ts" linenums="false" header="src/app/bypass-security.component.ts (trust-video-url)" region="trust-video-url">
</code-example> </code-example>

View File

@ -24,7 +24,7 @@ The `SwUpdate` service supports four separate operations:
The two update events, `available` and `activated`, are `Observable` properties of `SwUpdate`: The two update events, `available` and `activated`, are `Observable` properties of `SwUpdate`:
<code-example path="service-worker-getting-started/src/app/log-update.service.ts" linenums="false" title="log-update.service.ts" region="sw-update"> </code-example> <code-example path="service-worker-getting-started/src/app/log-update.service.ts" linenums="false" header="log-update.service.ts" region="sw-update"> </code-example>
You can use these events to notify the user of a pending update or to refresh their pages when the code they are running is out of date. You can use these events to notify the user of a pending update or to refresh their pages when the code they are running is out of date.
@ -35,7 +35,7 @@ It's possible to ask the service worker to check if any updates have been deploy
Do this with the `checkForUpdate()` method: Do this with the `checkForUpdate()` method:
<code-example path="service-worker-getting-started/src/app/check-for-update.service.ts" linenums="false" title="check-for-update.service.ts" region="sw-check-update"> </code-example> <code-example path="service-worker-getting-started/src/app/check-for-update.service.ts" linenums="false" header="check-for-update.service.ts" region="sw-check-update"> </code-example>
This method returns a `Promise` which indicates that the update check has completed successfully, though it does not indicate whether an update was discovered as a result of the check. Even if one is found, the service worker must still successfully download the changed files, which can fail. If successful, the `available` event will indicate availability of a new version of the app. This method returns a `Promise` which indicates that the update check has completed successfully, though it does not indicate whether an update was discovered as a result of the check. Even if one is found, the service worker must still successfully download the changed files, which can fail. If successful, the `available` event will indicate availability of a new version of the app.
@ -44,7 +44,7 @@ This method returns a `Promise` which indicates that the update check has comple
If the current tab needs to be updated to the latest app version immediately, it can ask to do so with the `activateUpdate()` method: If the current tab needs to be updated to the latest app version immediately, it can ask to do so with the `activateUpdate()` method:
<code-example path="service-worker-getting-started/src/app/prompt-update.service.ts" linenums="false" title="prompt-update.service.ts" region="sw-activate"> </code-example> <code-example path="service-worker-getting-started/src/app/prompt-update.service.ts" linenums="false" header="prompt-update.service.ts" region="sw-activate"> </code-example>
Doing this could break lazy-loading into currently running apps, especially if the lazy-loaded chunks use filenames with hashes, which change every version. Doing this could break lazy-loading into currently running apps, especially if the lazy-loaded chunks use filenames with hashes, which change every version.

View File

@ -43,7 +43,7 @@ for getting and setting the current HTML document title:
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:
<code-example path="set-document-title/src/app/app.component.ts" region="class" title="src/app/app.component.ts (class)" linenums="false"></code-example> <code-example path="set-document-title/src/app/app.component.ts" region="class" header="src/app/app.component.ts (class)" linenums="false"></code-example>
Bind that method to three anchor tags and voilà! Bind that method to three anchor tags and voilà!
@ -54,9 +54,9 @@ Bind that method to three anchor tags and voilà!
Here's the complete solution: Here's the complete solution:
<code-tabs> <code-tabs>
<code-pane title="src/main.ts" path="set-document-title/src/main.ts"></code-pane> <code-pane header="src/main.ts" path="set-document-title/src/main.ts"></code-pane>
<code-pane title="src/app/app.module.ts" path="set-document-title/src/app/app.module.ts"></code-pane> <code-pane header="src/app/app.module.ts" path="set-document-title/src/app/app.module.ts"></code-pane>
<code-pane title="src/app/app.component.ts" path="set-document-title/src/app/app.component.ts"></code-pane> <code-pane header="src/app/app.component.ts" path="set-document-title/src/app/app.component.ts"></code-pane>
</code-tabs> </code-tabs>
## Why provide the `Title` service in `bootstrap` ## Why provide the `Title` service in `bootstrap`

View File

@ -171,15 +171,15 @@ Focus on the following three TypeScript (`.ts`) files in the **`/src`** folder.
<code-tabs> <code-tabs>
<code-pane title="src/app/app.component.ts" path="setup/src/app/app.component.ts"> <code-pane header="src/app/app.component.ts" path="setup/src/app/app.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/app.module.ts" path="setup/src/app/app.module.ts"> <code-pane header="src/app/app.module.ts" path="setup/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="src/main.ts" path="setup/src/main.ts"> <code-pane header="src/main.ts" path="setup/src/main.ts">
</code-pane> </code-pane>

View File

@ -19,7 +19,7 @@ There are two ways to make a service a singleton in Angular:
Beginning with Angular 6.0, the preferred way to create a singleton services is to specify on the service that it should be provided in the application root. This is done by setting `providedIn` to `root` on the service's `@Injectable` decorator: Beginning with Angular 6.0, the preferred way to create a singleton services is to specify on the service that it should be provided in the application root. This is done by setting `providedIn` to `root` on the service's `@Injectable` decorator:
<code-example path="providers/src/app/user.service.0.ts" title="src/app/user.service.0.ts" linenums="false"> </code-example> <code-example path="providers/src/app/user.service.0.ts" header="src/app/user.service.0.ts" linenums="false"> </code-example>
For more detailed information on services, see the [Services](tutorial/toh-pt4) chapter of the For more detailed information on services, see the [Services](tutorial/toh-pt4) chapter of the
@ -69,19 +69,19 @@ the core `UserService`.
In the following example, the optional, injected `UserServiceConfig` In the following example, the optional, injected `UserServiceConfig`
extends the core `UserService`. If a `UserServiceConfig` exists, the `UserService` sets the user name from that config. extends the core `UserService`. If a `UserServiceConfig` exists, the `UserService` sets the user name from that config.
<code-example path="ngmodules/src/app/core/user.service.ts" region="ctor" title="src/app/core/user.service.ts (constructor)" linenums="false"> <code-example path="ngmodules/src/app/core/user.service.ts" region="ctor" header="src/app/core/user.service.ts (constructor)" linenums="false">
</code-example> </code-example>
Here's `forRoot()` that takes a `UserServiceConfig` object: Here's `forRoot()` that takes a `UserServiceConfig` object:
<code-example path="ngmodules/src/app/core/core.module.ts" region="for-root" title="src/app/core/core.module.ts (forRoot)" linenums="false"> <code-example path="ngmodules/src/app/core/core.module.ts" region="for-root" header="src/app/core/core.module.ts (forRoot)" linenums="false">
</code-example> </code-example>
Lastly, call it within the `imports` list of the `AppModule`. Lastly, call it within the `imports` list of the `AppModule`.
<code-example path="ngmodules/src/app/app.module.ts" region="import-for-root" title="src/app/app.module.ts (imports)" linenums="false"> <code-example path="ngmodules/src/app/app.module.ts" region="import-for-root" header="src/app/app.module.ts (imports)" linenums="false">
</code-example> </code-example>
@ -99,7 +99,7 @@ lazy-loaded module imports it too, the app can generate
To guard against a lazy-loaded module re-importing `CoreModule`, add the following `CoreModule` constructor. To guard against a lazy-loaded module re-importing `CoreModule`, add the following `CoreModule` constructor.
<code-example path="ngmodules/src/app/core/core.module.ts" region="ctor" title="src/app/core/core.module.ts" linenums="false"> <code-example path="ngmodules/src/app/core/core.module.ts" region="ctor" header="src/app/core/core.module.ts" linenums="false">
</code-example> </code-example>
@ -130,11 +130,11 @@ Here are the two files in their entirety for reference:
<code-tabs linenums="false"> <code-tabs linenums="false">
<code-pane <code-pane
title="app.module.ts" header="app.module.ts"
path="ngmodules/src/app/app.module.ts"> path="ngmodules/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane <code-pane
title="core.module.ts" header="core.module.ts"
region="whole-core-module" region="whole-core-module"
path="ngmodules/src/app/core/core.module.ts"> path="ngmodules/src/app/core/core.module.ts">
</code-pane> </code-pane>

View File

@ -31,7 +31,7 @@ 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.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif)" region="ngif"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngif)" region="ngif">
</code-example> </code-example>
@ -52,7 +52,7 @@ described in the [_Template Syntax_](guide/template-syntax) guide and seen in sa
Here's an example of them in a template: Here's an example of them in a template:
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (built-in)" region="built-in"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (built-in)" region="built-in">
</code-example> </code-example>
@ -121,7 +121,7 @@ You can [only apply one](guide/structural-directives#one-per-element) _structura
It takes a boolean expression and makes an entire chunk of the DOM appear or disappear. It takes a boolean expression and makes an entire chunk of the DOM appear or disappear.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-true)" region="ngif-true"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngif-true)" region="ngif-true">
</code-example> </code-example>
@ -150,7 +150,7 @@ The component and DOM nodes can be garbage-collected and free up memory.
A directive could hide the unwanted paragraph instead by setting its `display` style to `none`. A directive could hide the unwanted paragraph instead by setting its `display` style to `none`.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (display-none)" region="display-none"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (display-none)" region="display-none">
</code-example> </code-example>
@ -201,7 +201,7 @@ and wondered why it is necessary and what it does.
Here is `*ngIf` displaying the hero's name if `hero` exists. Here is `*ngIf` displaying the hero's name if `hero` exists.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (asterisk)" region="asterisk"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (asterisk)" region="asterisk">
</code-example> </code-example>
@ -211,7 +211,7 @@ The asterisk is "syntactic sugar" for something a bit more complicated.
Internally, Angular translates the `*ngIf` _attribute_ into a `<ng-template>` _element_, wrapped around the host element, like this. Internally, Angular translates the `*ngIf` _attribute_ into a `<ng-template>` _element_, wrapped around the host element, like this.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-template)" region="ngif-template"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngif-template)" region="ngif-template">
</code-example> </code-example>
@ -246,7 +246,7 @@ Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax to `
Here's a full-featured application of `NgFor`, written both ways: Here's a full-featured application of `NgFor`, written both ways:
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (inside-ngfor)" region="inside-ngfor"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (inside-ngfor)" region="inside-ngfor">
</code-example> </code-example>
@ -373,7 +373,7 @@ The Angular _NgSwitch_ is actually a set of cooperating directives: `NgSwitch`,
Here's an example. Here's an example.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngswitch)" region="ngswitch"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngswitch)" region="ngswitch">
</code-example> </code-example>
@ -409,7 +409,7 @@ As with other structural directives, the `NgSwitchCase` and `NgSwitchDefault`
can be desugared into the `<ng-template>` element form. can be desugared into the `<ng-template>` element form.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngswitch-template)" region="ngswitch-template"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngswitch-template)" region="ngswitch-template">
</code-example> </code-example>
@ -444,7 +444,7 @@ those elements disappear.
That's the fate of the middle "Hip!" in the phrase "Hip! Hip! Hooray!". That's the fate of the middle "Hip!" in the phrase "Hip! Hip! Hooray!".
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (template-tag)" region="template-tag"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (template-tag)" region="template-tag">
</code-example> </code-example>
@ -476,7 +476,7 @@ There's often a _root_ element that can and should host the structural directive
The list element (`<li>`) is a typical host element of an `NgFor` repeater. The list element (`<li>`) is a typical host element of an `NgFor` repeater.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngfor-li)" region="ngfor-li"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngfor-li)" region="ngfor-li">
</code-example> </code-example>
@ -486,7 +486,7 @@ When there isn't a host element, you can usually wrap the content in a native HT
such as a `<div>`, and attach the directive to that wrapper. such as a `<div>`, and attach the directive to that wrapper.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif)" region="ngif"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngif)" region="ngif">
</code-example> </code-example>
@ -501,7 +501,7 @@ 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.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-span)" region="ngif-span"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngif-span)" region="ngif-span">
</code-example> </code-example>
@ -510,7 +510,7 @@ For example, suppose you have the following paragraph layout.
You also have a CSS style rule that happens to apply to a `<span>` within a `<p>`aragraph. You also have a CSS style rule that happens to apply to a `<span>` within a `<p>`aragraph.
<code-example path="structural-directives/src/app/app.component.css" linenums="false" title="src/app/app.component.css (p-span)" region="p-span"> <code-example path="structural-directives/src/app/app.component.css" linenums="false" header="src/app/app.component.css (p-span)" region="p-span">
</code-example> </code-example>
@ -534,7 +534,7 @@ You can't wrap the _options_ in a conditional `<div>` or a `<span>`.
When you try this, When you try this,
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (select-span)" region="select-span"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (select-span)" region="select-span">
</code-example> </code-example>
@ -559,7 +559,7 @@ 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>`.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-ngcontainer)" region="ngif-ngcontainer"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngif-ngcontainer)" region="ngif-ngcontainer">
</code-example> </code-example>
@ -577,7 +577,7 @@ It renders properly.
Now conditionally exclude a _select_ `<option>` with `<ng-container>`. Now conditionally exclude a _select_ `<option>` with `<ng-container>`.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (select-ngcontainer)" region="select-ngcontainer"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (select-ngcontainer)" region="select-ngcontainer">
</code-example> </code-example>
@ -625,7 +625,7 @@ that does the opposite of `NgIf`.
`UnlessDirective` displays the content when the condition is ***false***. `UnlessDirective` displays the content when the condition is ***false***.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (appUnless-1)" region="appUnless-1"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (appUnless-1)" region="appUnless-1">
</code-example> </code-example>
@ -644,7 +644,7 @@ Creating a directive is similar to creating a component.
Here's how you might begin: Here's how you might begin:
<code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" title="src/app/unless.directive.ts (skeleton)" region="skeleton"> <code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" header="src/app/unless.directive.ts (skeleton)" region="skeleton">
</code-example> </code-example>
@ -679,7 +679,7 @@ and access the _view container_ through a
You inject both in the directive constructor as private variables of the class. You inject both in the directive constructor as private variables of the class.
<code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" title="src/app/unless.directive.ts (ctor)" region="ctor"> <code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" header="src/app/unless.directive.ts (ctor)" region="ctor">
</code-example> </code-example>
@ -702,7 +702,7 @@ Read about `@Input` in the [_Template Syntax_](guide/template-syntax#inputs-outp
<code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" title="src/app/unless.directive.ts (set)" region="set"> <code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" header="src/app/unless.directive.ts (set)" region="set">
</code-example> </code-example>
@ -722,7 +722,7 @@ Nobody reads the `appUnless` property so it doesn't need a getter.
The completed directive code looks like this: The completed directive code looks like this:
<code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" title="src/app/unless.directive.ts (excerpt)" region="no-docs"> <code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" header="src/app/unless.directive.ts (excerpt)" region="no-docs">
</code-example> </code-example>
@ -733,7 +733,7 @@ Add this directive to the `declarations` array of the AppModule.
Then create some HTML to try it. Then create some HTML to try it.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (appUnless)" region="appUnless"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (appUnless)" region="appUnless">
</code-example> </code-example>
@ -762,31 +762,31 @@ Here is the source from the `src/app/` folder.
<code-tabs> <code-tabs>
<code-pane title="app.component.ts" path="structural-directives/src/app/app.component.ts"> <code-pane header="app.component.ts" path="structural-directives/src/app/app.component.ts">
</code-pane> </code-pane>
<code-pane title="app.component.html" path="structural-directives/src/app/app.component.html"> <code-pane header="app.component.html" path="structural-directives/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane title="app.component.css" path="structural-directives/src/app/app.component.css"> <code-pane header="app.component.css" path="structural-directives/src/app/app.component.css">
</code-pane> </code-pane>
<code-pane title="app.module.ts" path="structural-directives/src/app/app.module.ts"> <code-pane header="app.module.ts" path="structural-directives/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="hero.ts" path="structural-directives/src/app/hero.ts"> <code-pane header="hero.ts" path="structural-directives/src/app/hero.ts">
</code-pane> </code-pane>
<code-pane title="hero-switch.components.ts" path="structural-directives/src/app/hero-switch.components.ts"> <code-pane header="hero-switch.components.ts" path="structural-directives/src/app/hero-switch.components.ts">
</code-pane> </code-pane>
<code-pane title="unless.directive.ts" path="structural-directives/src/app/unless.directive.ts"> <code-pane header="unless.directive.ts" path="structural-directives/src/app/unless.directive.ts">
</code-pane> </code-pane>

View File

@ -152,7 +152,7 @@ defines the `Hero` model object, and loads heroes from the server all in the sam
*Don't do this*. *Don't do this*.
<code-example path="styleguide/src/01-01/app/heroes/hero.component.avoid.ts" title="app/heroes/hero.component.ts"> <code-example path="styleguide/src/01-01/app/heroes/hero.component.avoid.ts" header="app/heroes/hero.component.ts">
</code-example> </code-example>
@ -164,31 +164,31 @@ supporting classes into their own, dedicated files.
<code-tabs> <code-tabs>
<code-pane title="main.ts" path="styleguide/src/01-01/main.ts"> <code-pane header="main.ts" path="styleguide/src/01-01/main.ts">
</code-pane> </code-pane>
<code-pane title="app/app.module.ts" path="styleguide/src/01-01/app/app.module.ts"> <code-pane header="app/app.module.ts" path="styleguide/src/01-01/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="app/app.component.ts" path="styleguide/src/01-01/app/app.component.ts"> <code-pane header="app/app.component.ts" path="styleguide/src/01-01/app/app.component.ts">
</code-pane> </code-pane>
<code-pane title="app/heroes/heroes.component.ts" path="styleguide/src/01-01/app/heroes/heroes.component.ts"> <code-pane header="app/heroes/heroes.component.ts" path="styleguide/src/01-01/app/heroes/heroes.component.ts">
</code-pane> </code-pane>
<code-pane title="app/heroes/shared/hero.service.ts" path="styleguide/src/01-01/app/heroes/shared/hero.service.ts"> <code-pane header="app/heroes/shared/hero.service.ts" path="styleguide/src/01-01/app/heroes/shared/hero.service.ts">
</code-pane> </code-pane>
<code-pane title="app/heroes/shared/hero.model.ts" path="styleguide/src/01-01/app/heroes/shared/hero.model.ts"> <code-pane header="app/heroes/shared/hero.model.ts" path="styleguide/src/01-01/app/heroes/shared/hero.model.ts">
</code-pane> </code-pane>
<code-pane title="app/heroes/shared/mock-heroes.ts" path="styleguide/src/01-01/app/heroes/shared/mock-heroes.ts"> <code-pane header="app/heroes/shared/mock-heroes.ts" path="styleguide/src/01-01/app/heroes/shared/mock-heroes.ts">
</code-pane> </code-pane>
@ -925,7 +925,7 @@ As always, strive for consistency.
<code-example path="styleguide/src/02-05/main.ts" title="main.ts"> <code-example path="styleguide/src/02-05/main.ts" header="main.ts">
</code-example> </code-example>
@ -962,7 +962,7 @@ As always, strive for consistency.
<code-example path="styleguide/src/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/shared/hero-button/hero-button.component.ts"> <code-example path="styleguide/src/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" header="app/heroes/shared/hero-button/hero-button.component.ts">
</code-example> </code-example>
@ -972,11 +972,11 @@ As always, strive for consistency.
<code-tabs> <code-tabs>
<code-pane title="app/heroes/shared/hero-button/hero-button.component.ts" path="styleguide/src/05-02/app/heroes/shared/hero-button/hero-button.component.ts" region="example"> <code-pane header="app/heroes/shared/hero-button/hero-button.component.ts" path="styleguide/src/05-02/app/heroes/shared/hero-button/hero-button.component.ts" region="example">
</code-pane> </code-pane>
<code-pane title="app/app.component.html" path="styleguide/src/05-02/app/app.component.html"> <code-pane header="app/app.component.html" path="styleguide/src/05-02/app/app.component.html">
</code-pane> </code-pane>
@ -1061,7 +1061,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
<code-example path="styleguide/src/02-07/app/heroes/hero.component.avoid.ts" region="example" title="app/heroes/hero.component.ts"> <code-example path="styleguide/src/02-07/app/heroes/hero.component.avoid.ts" region="example" header="app/heroes/hero.component.ts">
</code-example> </code-example>
@ -1069,7 +1069,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
<code-example path="styleguide/src/02-07/app/users/users.component.avoid.ts" region="example" title="app/users/users.component.ts"> <code-example path="styleguide/src/02-07/app/users/users.component.avoid.ts" region="example" header="app/users/users.component.ts">
</code-example> </code-example>
@ -1077,7 +1077,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
<code-example path="styleguide/src/02-07/app/heroes/hero.component.ts" region="example" title="app/heroes/hero.component.ts"> <code-example path="styleguide/src/02-07/app/heroes/hero.component.ts" region="example" header="app/heroes/hero.component.ts">
</code-example> </code-example>
@ -1085,7 +1085,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
<code-example path="styleguide/src/02-07/app/users/users.component.ts" region="example" title="app/users/users.component.ts"> <code-example path="styleguide/src/02-07/app/users/users.component.ts" region="example" header="app/users/users.component.ts">
</code-example> </code-example>
@ -1183,7 +1183,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
<code-example path="styleguide/src/02-08/app/shared/validate.directive.avoid.ts" region="example" title="app/shared/validate.directive.ts"> <code-example path="styleguide/src/02-08/app/shared/validate.directive.avoid.ts" region="example" header="app/shared/validate.directive.ts">
</code-example> </code-example>
@ -1191,7 +1191,7 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
<code-example path="styleguide/src/02-08/app/shared/validate.directive.ts" region="example" title="app/shared/validate.directive.ts"> <code-example path="styleguide/src/02-08/app/shared/validate.directive.ts" region="example" header="app/shared/validate.directive.ts">
</code-example> </code-example>
@ -1799,7 +1799,7 @@ By convention, upper camel case indicates a constructable asset.
<code-example path="styleguide/src/03-01/app/core/exception.service.avoid.ts" region="example" title="app/shared/exception.service.ts"> <code-example path="styleguide/src/03-01/app/core/exception.service.avoid.ts" region="example" header="app/shared/exception.service.ts">
</code-example> </code-example>
@ -1807,7 +1807,7 @@ By convention, upper camel case indicates a constructable asset.
<code-example path="styleguide/src/03-01/app/core/exception.service.ts" region="example" title="app/shared/exception.service.ts"> <code-example path="styleguide/src/03-01/app/core/exception.service.ts" region="example" header="app/shared/exception.service.ts">
</code-example> </code-example>
@ -1916,7 +1916,7 @@ It is rarely worth the effort to change them at the risk of breaking existing co
<code-example path="styleguide/src/03-02/app/core/data.service.ts" title="app/shared/data.service.ts"> <code-example path="styleguide/src/03-02/app/core/data.service.ts" header="app/shared/data.service.ts">
</code-example> </code-example>
@ -2020,7 +2020,7 @@ discourage the `I` prefix.
<code-example path="styleguide/src/03-03/app/core/hero-collector.service.avoid.ts" region="example" title="app/shared/hero-collector.service.ts"> <code-example path="styleguide/src/03-03/app/core/hero-collector.service.avoid.ts" region="example" header="app/shared/hero-collector.service.ts">
</code-example> </code-example>
@ -2028,7 +2028,7 @@ discourage the `I` prefix.
<code-example path="styleguide/src/03-03/app/core/hero-collector.service.ts" region="example" title="app/shared/hero-collector.service.ts"> <code-example path="styleguide/src/03-03/app/core/hero-collector.service.ts" region="example" header="app/shared/hero-collector.service.ts">
</code-example> </code-example>
@ -2098,7 +2098,7 @@ discourage the `I` prefix.
<code-example path="styleguide/src/03-04/app/core/toast.service.avoid.ts" region="example" title="app/shared/toast.service.ts"> <code-example path="styleguide/src/03-04/app/core/toast.service.avoid.ts" region="example" header="app/shared/toast.service.ts">
</code-example> </code-example>
@ -2106,7 +2106,7 @@ discourage the `I` prefix.
<code-example path="styleguide/src/03-04/app/core/toast.service.ts" region="example" title="app/shared/toast.service.ts"> <code-example path="styleguide/src/03-04/app/core/toast.service.ts" region="example" header="app/shared/toast.service.ts">
</code-example> </code-example>
@ -2176,7 +2176,7 @@ discourage the `I` prefix.
<code-example path="styleguide/src/03-06/app/heroes/shared/hero.service.avoid.ts" region="example" title="app/heroes/shared/hero.service.ts"> <code-example path="styleguide/src/03-06/app/heroes/shared/hero.service.avoid.ts" region="example" header="app/heroes/shared/hero.service.ts">
</code-example> </code-example>
@ -2184,7 +2184,7 @@ discourage the `I` prefix.
<code-example path="styleguide/src/03-06/app/heroes/shared/hero.service.ts" region="example" title="app/heroes/shared/hero.service.ts"> <code-example path="styleguide/src/03-06/app/heroes/shared/hero.service.ts" region="example" header="app/heroes/shared/hero.service.ts">
</code-example> </code-example>
@ -2932,7 +2932,7 @@ for example, in `/src/app`.
<code-example path="styleguide/src/04-08/app/app.module.ts" region="example" title="app/app.module.ts"> <code-example path="styleguide/src/04-08/app/app.module.ts" region="example" header="app/app.module.ts">
</code-example> </code-example>
@ -3284,27 +3284,27 @@ Yet there is a real danger of that happening if the `SharedModule` provides a se
<code-tabs> <code-tabs>
<code-pane title="app/shared/shared.module.ts" path="styleguide/src/04-10/app/shared/shared.module.ts"> <code-pane header="app/shared/shared.module.ts" path="styleguide/src/04-10/app/shared/shared.module.ts">
</code-pane> </code-pane>
<code-pane title="app/shared/init-caps.pipe.ts" path="styleguide/src/04-10/app/shared/init-caps.pipe.ts"> <code-pane header="app/shared/init-caps.pipe.ts" path="styleguide/src/04-10/app/shared/init-caps.pipe.ts">
</code-pane> </code-pane>
<code-pane title="app/shared/filter-text/filter-text.component.ts" path="styleguide/src/04-10/app/shared/filter-text/filter-text.component.ts"> <code-pane header="app/shared/filter-text/filter-text.component.ts" path="styleguide/src/04-10/app/shared/filter-text/filter-text.component.ts">
</code-pane> </code-pane>
<code-pane title="app/shared/filter-text/filter-text.service.ts" path="styleguide/src/04-10/app/shared/filter-text/filter-text.service.ts"> <code-pane header="app/shared/filter-text/filter-text.service.ts" path="styleguide/src/04-10/app/shared/filter-text/filter-text.service.ts">
</code-pane> </code-pane>
<code-pane title="app/heroes/heroes.component.ts" path="styleguide/src/04-10/app/heroes/heroes.component.ts"> <code-pane header="app/heroes/heroes.component.ts" path="styleguide/src/04-10/app/heroes/heroes.component.ts">
</code-pane> </code-pane>
<code-pane title="app/heroes/heroes.component.html" path="styleguide/src/04-10/app/heroes/heroes.component.html"> <code-pane header="app/heroes/heroes.component.html" path="styleguide/src/04-10/app/heroes/heroes.component.html">
</code-pane> </code-pane>
@ -3589,35 +3589,35 @@ Yet there is a real danger of that happening accidentally if the `CoreModule` pr
<code-tabs> <code-tabs>
<code-pane title="app/app.module.ts" path="styleguide/src/04-11/app/app.module.ts" region="example"> <code-pane header="app/app.module.ts" path="styleguide/src/04-11/app/app.module.ts" region="example">
</code-pane> </code-pane>
<code-pane title="app/core/core.module.ts" path="styleguide/src/04-11/app/core/core.module.ts"> <code-pane header="app/core/core.module.ts" path="styleguide/src/04-11/app/core/core.module.ts">
</code-pane> </code-pane>
<code-pane title="app/core/logger.service.ts" path="styleguide/src/04-11/app/core/logger.service.ts"> <code-pane header="app/core/logger.service.ts" path="styleguide/src/04-11/app/core/logger.service.ts">
</code-pane> </code-pane>
<code-pane title="app/core/nav/nav.component.ts" path="styleguide/src/04-11/app/core/nav/nav.component.ts"> <code-pane header="app/core/nav/nav.component.ts" path="styleguide/src/04-11/app/core/nav/nav.component.ts">
</code-pane> </code-pane>
<code-pane title="app/core/nav/nav.component.html" path="styleguide/src/04-11/app/core/nav/nav.component.html"> <code-pane header="app/core/nav/nav.component.html" path="styleguide/src/04-11/app/core/nav/nav.component.html">
</code-pane> </code-pane>
<code-pane title="app/core/spinner/spinner.component.ts" path="styleguide/src/04-11/app/core/spinner/spinner.component.ts"> <code-pane header="app/core/spinner/spinner.component.ts" path="styleguide/src/04-11/app/core/spinner/spinner.component.ts">
</code-pane> </code-pane>
<code-pane title="app/core/spinner/spinner.component.html" path="styleguide/src/04-11/app/core/spinner/spinner.component.html"> <code-pane header="app/core/spinner/spinner.component.html" path="styleguide/src/04-11/app/core/spinner/spinner.component.html">
</code-pane> </code-pane>
<code-pane title="app/core/spinner/spinner.service.ts" path="styleguide/src/04-11/app/core/spinner/spinner.service.ts"> <code-pane header="app/core/spinner/spinner.service.ts" path="styleguide/src/04-11/app/core/spinner/spinner.service.ts">
</code-pane> </code-pane>
@ -3685,11 +3685,11 @@ Only the root `AppModule` should import the `CoreModule`.
<code-tabs> <code-tabs>
<code-pane title="app/core/module-import-guard.ts" path="styleguide/src/04-12/app/core/module-import-guard.ts"> <code-pane header="app/core/module-import-guard.ts" path="styleguide/src/04-12/app/core/module-import-guard.ts">
</code-pane> </code-pane>
<code-pane title="app/core/core.module.ts" path="styleguide/src/04-12/app/core/core.module.ts"> <code-pane header="app/core/core.module.ts" path="styleguide/src/04-12/app/core/core.module.ts">
</code-pane> </code-pane>
@ -3808,7 +3808,7 @@ There are a few cases where you give a component an attribute, such as when you
</div> </div>
<code-example path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/hero-button/hero-button.component.ts"> <code-example path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" header="app/heroes/hero-button/hero-button.component.ts">
</code-example> </code-example>
@ -3816,7 +3816,7 @@ There are a few cases where you give a component an attribute, such as when you
<code-example path="styleguide/src/05-03/app/app.component.avoid.html" title="app/app.component.html"> <code-example path="styleguide/src/05-03/app/app.component.avoid.html" header="app/app.component.html">
</code-example> </code-example>
@ -3824,11 +3824,11 @@ There are a few cases where you give a component an attribute, such as when you
<code-tabs> <code-tabs>
<code-pane title="app/heroes/shared/hero-button/hero-button.component.ts" path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.ts" region="example"> <code-pane header="app/heroes/shared/hero-button/hero-button.component.ts" path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.ts" region="example">
</code-pane> </code-pane>
<code-pane title="app/app.component.html" path="styleguide/src/05-03/app/app.component.html"> <code-pane header="app/app.component.html" path="styleguide/src/05-03/app/app.component.html">
</code-pane> </code-pane>
@ -3936,7 +3936,7 @@ in those editors that support it; it won't help with CSS styles.
<code-example path="styleguide/src/05-04/app/heroes/heroes.component.avoid.ts" region="example" title="app/heroes/heroes.component.ts"> <code-example path="styleguide/src/05-04/app/heroes/heroes.component.avoid.ts" region="example" header="app/heroes/heroes.component.ts">
</code-example> </code-example>
@ -3946,15 +3946,15 @@ in those editors that support it; it won't help with CSS styles.
<code-tabs> <code-tabs>
<code-pane title="app/heroes/heroes.component.ts" path="styleguide/src/05-04/app/heroes/heroes.component.ts" region="example"> <code-pane header="app/heroes/heroes.component.ts" path="styleguide/src/05-04/app/heroes/heroes.component.ts" region="example">
</code-pane> </code-pane>
<code-pane title="app/heroes/heroes.component.html" path="styleguide/src/05-04/app/heroes/heroes.component.html"> <code-pane header="app/heroes/heroes.component.html" path="styleguide/src/05-04/app/heroes/heroes.component.html">
</code-pane> </code-pane>
<code-pane title="app/heroes/heroes.component.css" path="styleguide/src/05-04/app/heroes/heroes.component.css"> <code-pane header="app/heroes/heroes.component.css" path="styleguide/src/05-04/app/heroes/heroes.component.css">
</code-pane> </code-pane>
@ -4040,7 +4040,7 @@ Put it on the line above when doing so is clearly more readable.
<code-example path="styleguide/src/05-12/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/shared/hero-button/hero-button.component.ts"> <code-example path="styleguide/src/05-12/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" header="app/heroes/shared/hero-button/hero-button.component.ts">
</code-example> </code-example>
@ -4048,7 +4048,7 @@ Put it on the line above when doing so is clearly more readable.
<code-example path="styleguide/src/05-12/app/heroes/shared/hero-button/hero-button.component.ts" region="example" title="app/heroes/shared/hero-button/hero-button.component.ts"> <code-example path="styleguide/src/05-12/app/heroes/shared/hero-button/hero-button.component.ts" region="example" header="app/heroes/shared/hero-button/hero-button.component.ts">
</code-example> </code-example>
@ -4098,7 +4098,7 @@ and the directive name doesn't describe the property.
<code-example path="styleguide/src/05-13/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/shared/hero-button/hero-button.component.ts"> <code-example path="styleguide/src/05-13/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" header="app/heroes/shared/hero-button/hero-button.component.ts">
</code-example> </code-example>
@ -4106,7 +4106,7 @@ and the directive name doesn't describe the property.
<code-example path="styleguide/src/05-13/app/app.component.avoid.html" title="app/app.component.html"> <code-example path="styleguide/src/05-13/app/app.component.avoid.html" header="app/app.component.html">
</code-example> </code-example>
@ -4116,15 +4116,15 @@ and the directive name doesn't describe the property.
<code-tabs> <code-tabs>
<code-pane title="app/heroes/shared/hero-button/hero-button.component.ts" path="styleguide/src/05-13/app/heroes/shared/hero-button/hero-button.component.ts" region="example"> <code-pane header="app/heroes/shared/hero-button/hero-button.component.ts" path="styleguide/src/05-13/app/heroes/shared/hero-button/hero-button.component.ts" region="example">
</code-pane> </code-pane>
<code-pane title="app/heroes/shared/hero-button/hero-highlight.directive.ts" path="styleguide/src/05-13/app/heroes/shared/hero-highlight.directive.ts"> <code-pane header="app/heroes/shared/hero-button/hero-highlight.directive.ts" path="styleguide/src/05-13/app/heroes/shared/hero-highlight.directive.ts">
</code-pane> </code-pane>
<code-pane title="app/app.component.html" path="styleguide/src/05-13/app/app.component.html"> <code-pane header="app/app.component.html" path="styleguide/src/05-13/app/app.component.html">
</code-pane> </code-pane>
@ -4175,7 +4175,7 @@ helps instantly identify which members of the component serve which purpose.
<code-example path="styleguide/src/05-14/app/shared/toast/toast.component.avoid.ts" region="example" title="app/shared/toast/toast.component.ts"> <code-example path="styleguide/src/05-14/app/shared/toast/toast.component.avoid.ts" region="example" header="app/shared/toast/toast.component.ts">
</code-example> </code-example>
@ -4183,7 +4183,7 @@ helps instantly identify which members of the component serve which purpose.
<code-example path="styleguide/src/05-14/app/shared/toast/toast.component.ts" region="example" title="app/shared/toast/toast.component.ts"> <code-example path="styleguide/src/05-14/app/shared/toast/toast.component.ts" region="example" header="app/shared/toast/toast.component.ts">
</code-example> </code-example>
@ -4264,7 +4264,7 @@ helps instantly identify which members of the component serve which purpose.
<code-example path="styleguide/src/05-15/app/heroes/hero-list/hero-list.component.avoid.ts" title="app/heroes/hero-list/hero-list.component.ts"> <code-example path="styleguide/src/05-15/app/heroes/hero-list/hero-list.component.avoid.ts" header="app/heroes/hero-list/hero-list.component.ts">
</code-example> </code-example>
@ -4272,7 +4272,7 @@ helps instantly identify which members of the component serve which purpose.
<code-example path="styleguide/src/05-15/app/heroes/hero-list/hero-list.component.ts" region="example" title="app/heroes/hero-list/hero-list.component.ts"> <code-example path="styleguide/src/05-15/app/heroes/hero-list/hero-list.component.ts" region="example" header="app/heroes/hero-list/hero-list.component.ts">
</code-example> </code-example>
@ -4331,7 +4331,7 @@ helps instantly identify which members of the component serve which purpose.
<code-example path="styleguide/src/05-16/app/heroes/hero.component.avoid.ts" region="example" title="app/heroes/hero.component.ts"> <code-example path="styleguide/src/05-16/app/heroes/hero.component.avoid.ts" region="example" header="app/heroes/hero.component.ts">
</code-example> </code-example>
@ -4339,7 +4339,7 @@ helps instantly identify which members of the component serve which purpose.
<code-example path="styleguide/src/05-16/app/app.component.avoid.html" title="app/app.component.html"> <code-example path="styleguide/src/05-16/app/app.component.avoid.html" header="app/app.component.html">
</code-example> </code-example>
@ -4349,11 +4349,11 @@ helps instantly identify which members of the component serve which purpose.
<code-tabs> <code-tabs>
<code-pane title="app/heroes/hero.component.ts" path="styleguide/src/05-16/app/heroes/hero.component.ts" region="example"> <code-pane header="app/heroes/hero.component.ts" path="styleguide/src/05-16/app/heroes/hero.component.ts" region="example">
</code-pane> </code-pane>
<code-pane title="app/app.component.html" path="styleguide/src/05-16/app/app.component.html"> <code-pane header="app/app.component.html" path="styleguide/src/05-16/app/app.component.html">
</code-pane> </code-pane>
@ -4403,7 +4403,7 @@ helps instantly identify which members of the component serve which purpose.
<code-example path="styleguide/src/05-17/app/heroes/hero-list/hero-list.component.avoid.ts" region="example" title="app/heroes/hero-list/hero-list.component.ts"> <code-example path="styleguide/src/05-17/app/heroes/hero-list/hero-list.component.avoid.ts" region="example" header="app/heroes/hero-list/hero-list.component.ts">
</code-example> </code-example>
@ -4411,7 +4411,7 @@ helps instantly identify which members of the component serve which purpose.
<code-example path="styleguide/src/05-17/app/heroes/hero-list/hero-list.component.ts" region="example" title="app/heroes/hero-list/hero-list.component.ts"> <code-example path="styleguide/src/05-17/app/heroes/hero-list/hero-list.component.ts" region="example" header="app/heroes/hero-list/hero-list.component.ts">
</code-example> </code-example>
@ -4462,7 +4462,7 @@ helps instantly identify which members of the component serve which purpose.
<code-example path="styleguide/src/06-01/app/shared/highlight.directive.ts" region="example" title="app/shared/highlight.directive.ts"> <code-example path="styleguide/src/06-01/app/shared/highlight.directive.ts" region="example" header="app/shared/highlight.directive.ts">
</code-example> </code-example>
@ -4470,7 +4470,7 @@ helps instantly identify which members of the component serve which purpose.
<code-example path="styleguide/src/06-01/app/app.component.html" title="app/app.component.html"> <code-example path="styleguide/src/06-01/app/app.component.html" header="app/app.component.html">
</code-example> </code-example>
@ -4522,7 +4522,7 @@ directive's class and the metadata in the decorator associated with the directiv
<code-example path="styleguide/src/06-03/app/shared/validator.directive.ts" title="app/shared/validator.directive.ts"> <code-example path="styleguide/src/06-03/app/shared/validator.directive.ts" header="app/shared/validator.directive.ts">
</code-example> </code-example>
@ -4542,7 +4542,7 @@ Compare with the less preferred `host` metadata alternative.
<code-example path="styleguide/src/06-03/app/shared/validator2.directive.ts" title="app/shared/validator2.directive.ts"> <code-example path="styleguide/src/06-03/app/shared/validator2.directive.ts" header="app/shared/validator2.directive.ts">
</code-example> </code-example>
@ -4593,7 +4593,7 @@ Compare with the less preferred `host` metadata alternative.
<code-example path="styleguide/src/07-01/app/heroes/shared/hero.service.ts" region="example" title="app/heroes/shared/hero.service.ts"> <code-example path="styleguide/src/07-01/app/heroes/shared/hero.service.ts" region="example" header="app/heroes/shared/hero.service.ts">
</code-example> </code-example>
@ -4712,7 +4712,7 @@ Compare with the less preferred `host` metadata alternative.
</div> </div>
<code-example path="dependency-injection/src/app/tree-shaking/service.ts" title="src/app/treeshaking/service.ts" linenums="false"> </code-example> <code-example path="dependency-injection/src/app/tree-shaking/service.ts" header="src/app/treeshaking/service.ts" linenums="false"> </code-example>
@ -4760,7 +4760,7 @@ dependencies based on the declared types of that service's constructor parameter
<code-example path="styleguide/src/07-04/app/heroes/shared/hero-arena.service.avoid.ts" region="example" title="app/heroes/shared/hero-arena.service.ts"> <code-example path="styleguide/src/07-04/app/heroes/shared/hero-arena.service.avoid.ts" region="example" header="app/heroes/shared/hero-arena.service.ts">
</code-example> </code-example>
@ -4768,7 +4768,7 @@ dependencies based on the declared types of that service's constructor parameter
<code-example path="styleguide/src/07-04/app/heroes/shared/hero-arena.service.ts" region="example" title="app/heroes/shared/hero-arena.service.ts"> <code-example path="styleguide/src/07-04/app/heroes/shared/hero-arena.service.ts" region="example" header="app/heroes/shared/hero-arena.service.ts">
</code-example> </code-example>
@ -4884,7 +4884,7 @@ signatures. use those signatures to flag spelling and syntax mistakes.
<code-example path="styleguide/src/09-01/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/shared/hero-button/hero-button.component.ts"> <code-example path="styleguide/src/09-01/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" header="app/heroes/shared/hero-button/hero-button.component.ts">
</code-example> </code-example>
@ -4892,7 +4892,7 @@ signatures. use those signatures to flag spelling and syntax mistakes.
<code-example path="styleguide/src/09-01/app/heroes/shared/hero-button/hero-button.component.ts" region="example" title="app/heroes/shared/hero-button/hero-button.component.ts"> <code-example path="styleguide/src/09-01/app/heroes/shared/hero-button/hero-button.component.ts" region="example" header="app/heroes/shared/hero-button/hero-button.component.ts">
</code-example> </code-example>

View File

@ -46,12 +46,12 @@ Begin with the first form of data binding&mdash;interpolation&mdash;to see how m
You met the double-curly braces of interpolation, `{{` and `}}`, early in your Angular education. You met the double-curly braces of interpolation, `{{` and `}}`, early in your Angular education.
<code-example path="template-syntax/src/app/app.component.html" region="first-interpolation" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="first-interpolation" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments. You use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments.
<code-example path="template-syntax/src/app/app.component.html" region="title+image" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="title+image" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The text between the braces is often the name of a component property. Angular replaces that name with the The text between the braces is often the name of a component property. Angular replaces that name with the
@ -61,12 +61,12 @@ and "fills in the blanks", first displaying a bold application title and then a
More generally, the text between the braces is a **template expression** that Angular first **evaluates** More generally, the text between the braces is a **template expression** that Angular first **evaluates**
and then **converts to a string**. The following interpolation illustrates the point by adding the two numbers: and then **converts to a string**. The following interpolation illustrates the point by adding the two numbers:
<code-example path="template-syntax/src/app/app.component.html" region="sum-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="sum-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The expression can invoke methods of the host component such as `getVal()`, seen here: The expression can invoke methods of the host component such as `getVal()`, seen here:
<code-example path="template-syntax/src/app/app.component.html" region="sum-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="sum-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Angular evaluates all expressions in double curly braces, Angular evaluates all expressions in double curly braces,
@ -120,14 +120,14 @@ The *expression context* is typically the _component_ instance.
In the following snippets, the `title` within double-curly braces and the In the following snippets, the `title` within double-curly braces and the
`isUnchanged` in quotes refer to properties of the `AppComponent`. `isUnchanged` in quotes refer to properties of the `AppComponent`.
<code-example path="template-syntax/src/app/app.component.html" region="context-component-expression" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="context-component-expression" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
An expression may also refer to properties of the _template's_ context An expression may also refer to properties of the _template's_ context
such as a [template input variable](guide/template-syntax#template-input-variable) (`let hero`) such as a [template input variable](guide/template-syntax#template-input-variable) (`let hero`)
or a [template reference variable](guide/template-syntax#ref-vars) (`#heroInput`). or a [template reference variable](guide/template-syntax#ref-vars) (`#heroInput`).
<code-example path="template-syntax/src/app/app.component.html" region="context-var" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="context-var" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The context for terms in an expression is a blend of the _template variables_, The context for terms in an expression is a blend of the _template variables_,
@ -215,7 +215,7 @@ such as an element, component, or directive.
You'll see template statements in the [event binding](guide/template-syntax#event-binding) section, You'll see template statements in the [event binding](guide/template-syntax#event-binding) section,
appearing in quotes to the right of the `=`&nbsp;symbol as in `(event)="statement"`. appearing in quotes to the right of the `=`&nbsp;symbol as in `(event)="statement"`.
<code-example path="template-syntax/src/app/app.component.html" region="context-component-statement" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="context-component-statement" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
A template statement *has a side effect*. A template statement *has a side effect*.
@ -246,7 +246,7 @@ such as an event handling method of the component instance.
The *statement context* is typically the component instance. The *statement context* is typically the component instance.
The *deleteHero* in `(click)="deleteHero()"` is a method of the data-bound component. The *deleteHero* in `(click)="deleteHero()"` is a method of the data-bound component.
<code-example path="template-syntax/src/app/app.component.html" region="context-component-statement" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="context-component-statement" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The statement context may also refer to properties of the template's own context. The statement context may also refer to properties of the template's own context.
@ -255,7 +255,7 @@ a [template input variable](guide/template-syntax#template-input-variable) (`let
and a [template reference variable](guide/template-syntax#ref-vars) (`#heroForm`) and a [template reference variable](guide/template-syntax#ref-vars) (`#heroForm`)
are passed to an event handling method of the component. are passed to an event handling method of the component.
<code-example path="template-syntax/src/app/app.component.html" region="context-var-statement" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="context-var-statement" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Template context names take precedence over component context names. Template context names take precedence over component context names.
@ -384,7 +384,7 @@ It requires a new mental model.
In the normal course of HTML development, you create a visual structure with HTML elements, and In the normal course of HTML development, you create a visual structure with HTML elements, and
you modify those elements by setting element attributes with string constants. you modify those elements by setting element attributes with string constants.
<code-example path="template-syntax/src/app/app.component.html" region="img+button" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="img+button" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You still create a structure and initialize attribute values this way in Angular templates. You still create a structure and initialize attribute values this way in Angular templates.
@ -392,14 +392,14 @@ You still create a structure and initialize attribute values this way in Angular
Then you learn to create new elements with components that encapsulate HTML Then you learn to create new elements with components that encapsulate HTML
and drop them into templates as if they were native HTML elements. and drop them into templates as if they were native HTML elements.
<code-example path="template-syntax/src/app/app.component.html" region="hero-detail-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="hero-detail-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
That's HTML Plus. That's HTML Plus.
Then you learn about data binding. The first binding you meet might look like this: Then you learn about data binding. The first binding you meet might look like this:
<code-example path="template-syntax/src/app/app.component.html" region="disabled-button-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="disabled-button-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You'll get to that peculiar bracket notation in a moment. Looking beyond it, You'll get to that peculiar bracket notation in a moment. Looking beyond it,
@ -512,7 +512,7 @@ The following table summarizes:
Directive&nbsp;property Directive&nbsp;property
</td> </td>
<td> <td>
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-syntax-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-syntax-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
</td> </td>
</tr> </tr>
@ -526,7 +526,7 @@ The following table summarizes:
Directive&nbsp;event Directive&nbsp;event
</td> </td>
<td> <td>
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-syntax-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="event-binding-syntax-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
</td> </td>
</tr> </tr>
@ -538,7 +538,7 @@ The following table summarizes:
Event and property Event and property
</td> </td>
<td> <td>
<code-example path="template-syntax/src/app/app.component.html" region="2-way-binding-syntax-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="2-way-binding-syntax-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
</td> </td>
</tr> </tr>
@ -551,7 +551,7 @@ The following table summarizes:
(the&nbsp;exception) (the&nbsp;exception)
</td> </td>
<td> <td>
<code-example path="template-syntax/src/app/app.component.html" region="attribute-binding-syntax-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="attribute-binding-syntax-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
</td> </td>
</tr> </tr>
@ -563,7 +563,7 @@ The following table summarizes:
<code>class</code> property <code>class</code> property
</td> </td>
<td> <td>
<code-example path="template-syntax/src/app/app.component.html" region="class-binding-syntax-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="class-binding-syntax-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
</td> </td>
</tr> </tr>
@ -575,7 +575,7 @@ The following table summarizes:
<code>style</code> property <code>style</code> property
</td> </td>
<td> <td>
<code-example path="template-syntax/src/app/app.component.html" region="style-binding-syntax-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="style-binding-syntax-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
</td> </td>
</tr> </tr>
@ -595,23 +595,23 @@ The binding sets the property to the value of a [template expression](guide/temp
The most common property binding sets an element property to a component property value. An example is The most common property binding sets an element property to a component property value. An example is
binding the `src` property of an image element to a component's `heroImageUrl` property: binding the `src` property of an image element to a component's `heroImageUrl` property:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Another example is disabling a button when the component says that it `isUnchanged`: Another example is disabling a button when the component says that it `isUnchanged`:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Another is setting a property of a directive: Another is setting a property of a directive:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-3" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Yet another is setting the model property of a custom component (a great way Yet another is setting the model property of a custom component (a great way
for parent and child components to communicate): for parent and child components to communicate):
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-4" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-4" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
### One-way *in* ### One-way *in*
@ -641,12 +641,12 @@ See the API reference for
An element property between enclosing square brackets identifies the target property. An element property between enclosing square brackets identifies the target property.
The target property in the following code is the image element's `src` property. The target property in the following code is the image element's `src` property.
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Some people prefer the `bind-` prefix alternative, known as the *canonical form*: Some people prefer the `bind-` prefix alternative, known as the *canonical form*:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-5" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-5" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The target name is always the name of a property, even when it appears to be the name of something else. The target name is always the name of a property, even when it appears to be the name of something else.
@ -656,7 +656,7 @@ Element properties may be the more common targets,
but Angular looks first to see if the name is a property of a known directive, but Angular looks first to see if the name is a property of a known directive,
as it is in the following example: as it is in the following example:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-3" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -692,7 +692,7 @@ Return an object if the target property expects an object.
The `hero` property of the `HeroDetail` component expects a `Hero` object, which is exactly what you're sending in the property binding: The `hero` property of the `HeroDetail` component expects a `Hero` object, which is exactly what you're sending in the property binding:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-4" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-4" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
### Remember the brackets ### Remember the brackets
@ -704,7 +704,7 @@ It does *not* evaluate the string!
Don't make the following mistake: Don't make the following mistake:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-6" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-6" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
{@a one-time-initialization} {@a one-time-initialization}
@ -722,7 +722,7 @@ just as well for directive and component property initialization.
The following example initializes the `prefix` property of the `HeroDetailComponent` to a fixed string, The following example initializes the `prefix` property of the `HeroDetailComponent` to a fixed string,
not a template expression. Angular sets it and forgets about it. not a template expression. Angular sets it and forgets about it.
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-7" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-7" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The `[hero]` binding, on the other hand, remains a live binding to the component's `currentHero` property. The `[hero]` binding, on the other hand, remains a live binding to the component's `currentHero` property.
@ -734,7 +734,7 @@ The `[hero]` binding, on the other hand, remains a live binding to the component
You often have a choice between interpolation and property binding. You often have a choice between interpolation and property binding.
The following binding pairs do the same thing: The following binding pairs do the same thing:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-vs-interpolation" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-vs-interpolation" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
_Interpolation_ is a convenient alternative to _property binding_ in many cases. _Interpolation_ is a convenient alternative to _property binding_ in many cases.
@ -750,7 +750,7 @@ When setting an element property to a non-string data value, you must use _prope
Imagine the following *malicious content*. Imagine the following *malicious content*.
<code-example path="template-syntax/src/app/app.component.ts" region="evil-title" title="src/app/app.component.ts" linenums="false"> <code-example path="template-syntax/src/app/app.component.ts" region="evil-title" header="src/app/app.component.ts" linenums="false">
</code-example> </code-example>
Fortunately, Angular data binding is on alert for dangerous HTML. Fortunately, Angular data binding is on alert for dangerous HTML.
@ -758,7 +758,7 @@ It [*sanitizes*](guide/security#sanitization-and-security-contexts) the values b
It **will not** allow HTML with script tags to leak into the browser, neither with interpolation It **will not** allow HTML with script tags to leak into the browser, neither with interpolation
nor property binding. nor property binding.
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-vs-interpolation-sanitization" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-vs-interpolation-sanitization" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Interpolation handles the script tags differently than property binding but both approaches render the Interpolation handles the script tags differently than property binding but both approaches render the
@ -826,7 +826,7 @@ You then set the attribute value, using an expression that resolves to a string.
Bind `[attr.colspan]` to a calculated value: Bind `[attr.colspan]` to a calculated value:
<code-example path="template-syntax/src/app/app.component.html" region="attrib-binding-colspan" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="attrib-binding-colspan" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Here's how the table renders: Here's how the table renders:
@ -839,7 +839,7 @@ Here's how the table renders:
One of the primary use cases for attribute binding One of the primary use cases for attribute binding
is to set ARIA attributes, as in this example: is to set ARIA attributes, as in this example:
<code-example path="template-syntax/src/app/app.component.html" region="attrib-binding-aria" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="attrib-binding-aria" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -857,19 +857,19 @@ optionally followed by a dot (`.`) and the name of a CSS class: `[class.class-na
The following examples show how to add and remove the application's "special" class The following examples show how to add and remove the application's "special" class
with class bindings. Here's how to set the attribute without binding: with class bindings. Here's how to set the attribute without binding:
<code-example path="template-syntax/src/app/app.component.html" region="class-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="class-binding-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You can replace that with a binding to a string of the desired class names; this is an all-or-nothing, replacement binding. You can replace that with a binding to a string of the desired class names; this is an all-or-nothing, replacement binding.
<code-example path="template-syntax/src/app/app.component.html" region="class-binding-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="class-binding-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Finally, you can bind to a specific class name. Finally, you can bind to a specific class name.
Angular adds the class when the template expression evaluates to truthy. Angular adds the class when the template expression evaluates to truthy.
It removes the class when the expression is falsy. It removes the class when the expression is falsy.
<code-example path="template-syntax/src/app/app.component.html" region="class-binding-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="class-binding-3" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -890,13 +890,13 @@ Style binding syntax resembles property binding.
Instead of an element property between brackets, start with the prefix `style`, Instead of an element property between brackets, start with the prefix `style`,
followed by a dot (`.`) and the name of a CSS style property: `[style.style-property]`. followed by a dot (`.`) and the name of a CSS style property: `[style.style-property]`.
<code-example path="template-syntax/src/app/app.component.html" region="style-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="style-binding-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Some style binding styles have a unit extension. Some style binding styles have a unit extension.
The following example conditionally sets the font size in “em” and “%” units . The following example conditionally sets the font size in “em” and “%” units .
<code-example path="template-syntax/src/app/app.component.html" region="style-binding-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="style-binding-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -936,7 +936,7 @@ within parentheses on the left of an equal sign, and a quoted
The following event binding listens for the button's click events, calling The following event binding listens for the button's click events, calling
the component's `onSave()` method whenever a click occurs: the component's `onSave()` method whenever a click occurs:
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
### Target event ### Target event
@ -944,18 +944,18 @@ the component's `onSave()` method whenever a click occurs:
A **name between parentheses** &mdash; for example, `(click)` &mdash; A **name between parentheses** &mdash; for example, `(click)` &mdash;
identifies the target event. In the following example, the target is the button's click event. identifies the target event. In the following example, the target is the button's click event.
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Some people prefer the `on-` prefix alternative, known as the **canonical form**: Some people prefer the `on-` prefix alternative, known as the **canonical form**:
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="event-binding-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Element events may be the more common targets, but Angular looks first to see if the name matches an event property Element events may be the more common targets, but Angular looks first to see if the name matches an event property
of a known directive, as it does in the following example: of a known directive, as it does in the following example:
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="event-binding-3" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -987,7 +987,7 @@ with properties such as `target` and `target.value`.
Consider this example: Consider this example:
<code-example path="template-syntax/src/app/app.component.html" region="without-NgModel" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="without-NgModel" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
This code sets the input box `value` property by binding to the `name` property. This code sets the input box `value` property by binding to the `name` property.
@ -1017,10 +1017,10 @@ The best it can do is raise an event reporting the user's delete request.
Here are the pertinent excerpts from that `HeroDetailComponent`: Here are the pertinent excerpts from that `HeroDetailComponent`:
<code-example path="template-syntax/src/app/hero-detail.component.ts" linenums="false" title="src/app/hero-detail.component.ts (template)" region="template-1"> <code-example path="template-syntax/src/app/hero-detail.component.ts" linenums="false" header="src/app/hero-detail.component.ts (template)" region="template-1">
</code-example> </code-example>
<code-example path="template-syntax/src/app/hero-detail.component.ts" linenums="false" title="src/app/hero-detail.component.ts (deleteRequest)" region="deleteRequest"> <code-example path="template-syntax/src/app/hero-detail.component.ts" linenums="false" header="src/app/hero-detail.component.ts (deleteRequest)" region="deleteRequest">
</code-example> </code-example>
The component defines a `deleteRequest` property that returns an `EventEmitter`. The component defines a `deleteRequest` property that returns an `EventEmitter`.
@ -1029,7 +1029,7 @@ telling the `EventEmitter` to emit a `Hero` object.
Now imagine a hosting parent component that binds to the `HeroDetailComponent`'s `deleteRequest` event. Now imagine a hosting parent component that binds to the `HeroDetailComponent`'s `deleteRequest` event.
<code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (event-binding-to-component)" region="event-binding-to-component"> <code-example path="template-syntax/src/app/app.component.html" linenums="false" header="src/app/app.component.html (event-binding-to-component)" region="event-binding-to-component">
</code-example> </code-example>
When the `deleteRequest` event fires, Angular calls the parent component's `deleteHero` method, When the `deleteRequest` event fires, Angular calls the parent component's `deleteHero` method,
@ -1075,7 +1075,7 @@ and a corresponding event named `xChange`.
Here's a `SizerComponent` that fits the pattern. Here's a `SizerComponent` that fits the pattern.
It has a `size` value property and a companion `sizeChange` event: It has a `size` value property and a companion `sizeChange` event:
<code-example path="template-syntax/src/app/sizer.component.ts" title="src/app/sizer.component.ts"> <code-example path="template-syntax/src/app/sizer.component.ts" header="src/app/sizer.component.ts">
</code-example> </code-example>
The initial `size` is an input value from a property binding. The initial `size` is an input value from a property binding.
@ -1084,7 +1084,7 @@ and then raises (_emits_) the `sizeChange` event with the adjusted size.
Here's an example in which the `AppComponent.fontSizePx` is two-way bound to the `SizerComponent`: Here's an example in which the `AppComponent.fontSizePx` is two-way bound to the `SizerComponent`:
<code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (two-way-1)" region="two-way-1"> <code-example path="template-syntax/src/app/app.component.html" linenums="false" header="src/app/app.component.html (two-way-1)" region="two-way-1">
</code-example> </code-example>
The `AppComponent.fontSizePx` establishes the initial `SizerComponent.size` value. The `AppComponent.fontSizePx` establishes the initial `SizerComponent.size` value.
@ -1095,7 +1095,7 @@ making the displayed text bigger or smaller.
The two-way binding syntax is really just syntactic sugar for a _property_ binding and an _event_ binding. The two-way binding syntax is really just syntactic sugar for a _property_ binding and an _event_ binding.
Angular _desugars_ the `SizerComponent` binding into this: Angular _desugars_ the `SizerComponent` binding into this:
<code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (two-way-2)" region="two-way-2"> <code-example path="template-syntax/src/app/app.component.html" linenums="false" header="src/app/app.component.html (two-way-2)" region="two-way-2">
</code-example> </code-example>
The `$event` variable contains the payload of the `SizerComponent.sizeChange` event. The `$event` variable contains the payload of the `SizerComponent.sizeChange` event.
@ -1123,7 +1123,7 @@ You don't need many of those directives in Angular.
You can often achieve the same results with the more capable and expressive Angular binding system. You can often achieve the same results with the more capable and expressive Angular binding system.
Why create a directive to handle a click when you can write a simple binding such as this? Why create a directive to handle a click when you can write a simple binding such as this?
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You still benefit from directives that simplify complex tasks. You still benefit from directives that simplify complex tasks.
@ -1165,7 +1165,7 @@ You can bind to the `ngClass` to add or remove several classes simultaneously.
A [class binding](guide/template-syntax#class-binding) is a good way to add or remove a *single* class. A [class binding](guide/template-syntax#class-binding) is a good way to add or remove a *single* class.
<code-example path="template-syntax/src/app/app.component.html" region="class-binding-3a" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="class-binding-3a" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
To add or remove *many* CSS classes at the same time, the `NgClass` directive may be the better choice. To add or remove *many* CSS classes at the same time, the `NgClass` directive may be the better choice.
@ -1178,12 +1178,12 @@ Consider a `setCurrentClasses` component method that sets a component property,
`currentClasses` with an object that adds or removes three classes based on the `currentClasses` with an object that adds or removes three classes based on the
`true`/`false` state of three other component properties: `true`/`false` state of three other component properties:
<code-example path="template-syntax/src/app/app.component.ts" region="setClasses" title="src/app/app.component.ts" linenums="false"> <code-example path="template-syntax/src/app/app.component.ts" region="setClasses" header="src/app/app.component.ts" linenums="false">
</code-example> </code-example>
Adding an `ngClass` property binding to `currentClasses` sets the element's classes accordingly: Adding an `ngClass` property binding to `currentClasses` sets the element's classes accordingly:
<code-example path="template-syntax/src/app/app.component.html" region="NgClass-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgClass-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -1203,7 +1203,7 @@ With `NgStyle` you can set many inline styles simultaneously.
A [style binding](guide/template-syntax#style-binding) is an easy way to set a *single* style value. A [style binding](guide/template-syntax#style-binding) is an easy way to set a *single* style value.
<code-example path="template-syntax/src/app/app.component.html" region="NgStyle-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgStyle-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
To set *many* inline styles at the same time, the `NgStyle` directive may be the better choice. To set *many* inline styles at the same time, the `NgStyle` directive may be the better choice.
@ -1214,12 +1214,12 @@ Each key of the object is a style name; its value is whatever is appropriate for
Consider a `setCurrentStyles` component method that sets a component property, `currentStyles` Consider a `setCurrentStyles` component method that sets a component property, `currentStyles`
with an object that defines three styles, based on the state of three other component properties: with an object that defines three styles, based on the state of three other component properties:
<code-example path="template-syntax/src/app/app.component.ts" region="setStyles" title="src/app/app.component.ts" linenums="false"> <code-example path="template-syntax/src/app/app.component.ts" region="setStyles" header="src/app/app.component.ts" linenums="false">
</code-example> </code-example>
Adding an `ngStyle` property binding to `currentStyles` sets the element's styles accordingly: Adding an `ngStyle` property binding to `currentStyles` sets the element's styles accordingly:
<code-example path="template-syntax/src/app/app.component.html" region="NgStyle-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgStyle-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -1240,7 +1240,7 @@ update that property when the user makes changes.
Two-way data binding with the `NgModel` directive makes that easy. Here's an example: Two-way data binding with the `NgModel` directive makes that easy. Here's an example:
<code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (NgModel-1)" region="NgModel-1"> <code-example path="template-syntax/src/app/app.component.html" linenums="false" header="src/app/app.component.html (NgModel-1)" region="NgModel-1">
</code-example> </code-example>
#### _FormsModule_ is required to use _ngModel_ #### _FormsModule_ is required to use _ngModel_
@ -1252,7 +1252,7 @@ Learn more about the `FormsModule` and `ngModel` in the
Here's how to import the `FormsModule` to make `[(ngModel)]` available. Here's how to import the `FormsModule` to make `[(ngModel)]` available.
<code-example path="template-syntax/src/app/app.module.1.ts" linenums="false" title="src/app/app.module.ts (FormsModule import)"> <code-example path="template-syntax/src/app/app.module.1.ts" linenums="false" header="src/app/app.module.ts (FormsModule import)">
</code-example> </code-example>
#### Inside <span class="syntax">[(ngModel)]</span> #### Inside <span class="syntax">[(ngModel)]</span>
@ -1261,7 +1261,7 @@ Looking back at the `name` binding, note that
you could have achieved the same result with separate bindings to you could have achieved the same result with separate bindings to
the `<input>` element's `value` property and `input` event. the `<input>` element's `value` property and `input` event.
<code-example path="template-syntax/src/app/app.component.html" region="without-NgModel" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="without-NgModel" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
That's cumbersome. Who can remember which element property to set and which element event emits user changes? That's cumbersome. Who can remember which element property to set and which element event emits user changes?
@ -1270,7 +1270,7 @@ Who wants to look that up each time?
That `ngModel` directive hides these onerous details behind its own `ngModel` input and `ngModelChange` output properties. That `ngModel` directive hides these onerous details behind its own `ngModel` input and `ngModelChange` output properties.
<code-example path="template-syntax/src/app/app.component.html" region="NgModel-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgModel-3" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -1302,7 +1302,7 @@ You shouldn't have to mention the data property twice. Angular should be able to
the component's data property and set it the component's data property and set it
with a single declaration, which it can with the `[(ngModel)]` syntax: with a single declaration, which it can with the `[(ngModel)]` syntax:
<code-example path="template-syntax/src/app/app.component.html" region="NgModel-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgModel-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Is `[(ngModel)]` all you need? Is there ever a reason to fall back to its expanded form? Is `[(ngModel)]` all you need? Is there ever a reason to fall back to its expanded form?
@ -1312,7 +1312,7 @@ If you need to do something more or something different, you can write the expan
The following contrived example forces the input value to uppercase: The following contrived example forces the input value to uppercase:
<code-example path="template-syntax/src/app/app.component.html" region="NgModel-4" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgModel-4" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Here are all variations in action, including the uppercase version: Here are all variations in action, including the uppercase version:
@ -1358,7 +1358,7 @@ You can add or remove an element from the DOM by applying an `NgIf` directive to
that element (called the _host element_). that element (called the _host element_).
Bind the directive to a condition expression like `isActive` in this example. Bind the directive to a condition expression like `isActive` in this example.
<code-example path="template-syntax/src/app/app.component.html" region="NgIf-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgIf-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-critical"> <div class="alert is-critical">
@ -1376,7 +1376,7 @@ from the DOM, destroying that component and all of its sub-components.
You can control the visibility of an element with a You can control the visibility of an element with a
[class](guide/template-syntax#class-binding) or [style](guide/template-syntax#style-binding) binding: [class](guide/template-syntax#class-binding) or [style](guide/template-syntax#style-binding) binding:
<code-example path="template-syntax/src/app/app.component.html" region="NgIf-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgIf-3" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Hiding an element is quite different from removing an element with `NgIf`. Hiding an element is quite different from removing an element with `NgIf`.
@ -1404,7 +1404,7 @@ Here we see `NgIf` guarding two `<div>`s.
The `currentHero` name will appear only when there is a `currentHero`. The `currentHero` name will appear only when there is a `currentHero`.
The `nullHero` will never be displayed. The `nullHero` will never be displayed.
<code-example path="template-syntax/src/app/app.component.html" region="NgIf-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgIf-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -1428,12 +1428,12 @@ You tell Angular to use that block as a template for rendering each item in the
Here is an example of `NgForOf` applied to a simple `<div>`: Here is an example of `NgForOf` applied to a simple `<div>`:
<code-example path="template-syntax/src/app/app.component.html" region="NgFor-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgFor-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You can also apply an `NgForOf` to a component element, as in this example: You can also apply an `NgForOf` to a component element, as in this example:
<code-example path="template-syntax/src/app/app.component.html" region="NgFor-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgFor-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-critical"> <div class="alert is-critical">
@ -1476,7 +1476,7 @@ You reference the `hero` input variable within the `NgForOf` host element
Here it is referenced first in an interpolation Here it is referenced first in an interpolation
and then passed in a binding to the `hero` property of the `<hero-detail>` component. and then passed in a binding to the `hero` property of the `<hero-detail>` component.
<code-example path="template-syntax/src/app/app.component.html" region="NgFor-1-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgFor-1-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Learn more about _template input variables_ in the Learn more about _template input variables_ in the
@ -1489,7 +1489,7 @@ You can capture the `index` in a template input variable and use it in the templ
The next example captures the `index` in a variable named `i` and displays it with the hero name like this. The next example captures the `index` in a variable named `i` and displays it with the hero name like this.
<code-example path="template-syntax/src/app/app.component.html" region="NgFor-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgFor-3" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -1517,12 +1517,12 @@ Angular can avoid this churn with `trackBy`.
Add a method to the component that returns the value `NgForOf` _should_ track. Add a method to the component that returns the value `NgForOf` _should_ track.
In this case, that value is the hero's `id`. In this case, that value is the hero's `id`.
<code-example path="template-syntax/src/app/app.component.ts" region="trackByHeroes" title="src/app/app.component.ts" linenums="false"> <code-example path="template-syntax/src/app/app.component.ts" region="trackByHeroes" header="src/app/app.component.ts" linenums="false">
</code-example> </code-example>
In the microsyntax expression, set `trackBy` to this method. In the microsyntax expression, set `trackBy` to this method.
<code-example path="template-syntax/src/app/app.component.html" region="trackBy" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="trackBy" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Here is an illustration of the _trackBy_ effect. Here is an illustration of the _trackBy_ effect.
@ -1550,7 +1550,7 @@ Angular puts only the *selected* element into the DOM.
*NgSwitch* is actually a set of three, cooperating directives: *NgSwitch* is actually a set of three, cooperating directives:
`NgSwitch`, `NgSwitchCase`, and `NgSwitchDefault` as seen in this example. `NgSwitch`, `NgSwitchCase`, and `NgSwitchDefault` as seen in this example.
<code-example path="template-syntax/src/app/app.component.html" region="NgSwitch" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgSwitch" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<figure> <figure>
@ -1580,7 +1580,7 @@ which is bound to the `currentHero` of the parent component.
Switch directives work as well with native elements and web components too. Switch directives work as well with native elements and web components too.
For example, you could replace the `<confused-hero>` switch case with the following. For example, you could replace the `<confused-hero>` switch case with the following.
<code-example path="template-syntax/src/app/app.component.html" region="NgSwitch-div" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgSwitch-div" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<hr/> <hr/>
@ -1600,14 +1600,14 @@ It can also be a reference to an Angular component or directive or a
Use the hash symbol (#) to declare a reference variable. Use the hash symbol (#) to declare a reference variable.
The `#phone` declares a `phone` variable on an `<input>` element. The `#phone` declares a `phone` variable on an `<input>` element.
<code-example path="template-syntax/src/app/app.component.html" region="ref-var" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="ref-var" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You can refer to a template reference variable _anywhere_ in the template. You can refer to a template reference variable _anywhere_ in the template.
The `phone` variable declared on this `<input>` is The `phone` variable declared on this `<input>` is
consumed in a `<button>` on the other side of the template consumed in a `<button>` on the other side of the template
<code-example path="template-syntax/src/app/app.component.html" region="ref-phone" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="ref-phone" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<h3 class="no-toc">How a reference variable gets its value</h3> <h3 class="no-toc">How a reference variable gets its value</h3>
@ -1620,7 +1620,7 @@ The `NgForm` directive does that.
The following is a *simplified* version of the form example in the [Forms](guide/forms) guide. The following is a *simplified* version of the form example in the [Forms](guide/forms) guide.
<code-example path="template-syntax/src/app/hero-form.component.html" title="src/app/hero-form.component.html" linenums="false"> <code-example path="template-syntax/src/app/hero-form.component.html" header="src/app/hero-form.component.html" linenums="false">
</code-example> </code-example>
A template reference variable, `heroForm`, appears three times in this example, separated A template reference variable, `heroForm`, appears three times in this example, separated
@ -1650,7 +1650,7 @@ The runtime value will be unpredictable.
You can use the `ref-` prefix alternative to `#`. You can use the `ref-` prefix alternative to `#`.
This example declares the `fax` variable as `ref-fax` instead of `#fax`. This example declares the `fax` variable as `ref-fax` instead of `#fax`.
<code-example path="template-syntax/src/app/app.component.html" region="ref-fax" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="ref-fax" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -1682,7 +1682,7 @@ because this topic is mostly a concern for component authors.
You are usually binding a template to its _own component class_. You are usually binding a template to its _own component class_.
In such binding expressions, the component's property or method is to the _right_ of the (`=`). In such binding expressions, the component's property or method is to the _right_ of the (`=`).
<code-example path="template-syntax/src/app/app.component.html" region="io-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="io-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The `iconUrl` and `onSave` are members of the `AppComponent` class. The `iconUrl` and `onSave` are members of the `AppComponent` class.
@ -1704,7 +1704,7 @@ In such bindings, the _other_ component's property is to the _left_ of the (`=`)
In the following example, the `AppComponent` template binds `AppComponent` class members to properties of the `HeroDetailComponent` whose selector is `'app-hero-detail'`. In the following example, the `AppComponent` template binds `AppComponent` class members to properties of the `HeroDetailComponent` whose selector is `'app-hero-detail'`.
<code-example path="template-syntax/src/app/app.component.html" region="io-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="io-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The Angular compiler _may_ reject these bindings with errors like this one: The Angular compiler _may_ reject these bindings with errors like this one:
@ -1753,7 +1753,7 @@ That _other way_ is the `@Input()` and `@Output()` decorators.
In the sample for this guide, the bindings to `HeroDetailComponent` do not fail In the sample for this guide, the bindings to `HeroDetailComponent` do not fail
because the data bound properties are annotated with `@Input()` and `@Output()` decorators. because the data bound properties are annotated with `@Input()` and `@Output()` decorators.
<code-example path="template-syntax/src/app/hero-detail.component.ts" region="input-output-1" title="src/app/hero-detail.component.ts" linenums="false"> <code-example path="template-syntax/src/app/hero-detail.component.ts" region="input-output-1" header="src/app/hero-detail.component.ts" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -1761,7 +1761,7 @@ because the data bound properties are annotated with `@Input()` and `@Output()`
Alternatively, you can identify members in the `inputs` and `outputs` arrays Alternatively, you can identify members in the `inputs` and `outputs` arrays
of the directive metadata, as in this example: of the directive metadata, as in this example:
<code-example path="template-syntax/src/app/hero-detail.component.ts" region="input-output-2" title="src/app/hero-detail.component.ts" linenums="false"> <code-example path="template-syntax/src/app/hero-detail.component.ts" region="input-output-2" header="src/app/hero-detail.component.ts" linenums="false">
</code-example> </code-example>
</div> </div>
@ -1794,7 +1794,7 @@ Directive consumers expect to bind to the name of the directive.
For example, when you apply a directive with a `myClick` selector to a `<div>` tag, For example, when you apply a directive with a `myClick` selector to a `<div>` tag,
you expect to bind to an event property that is also called `myClick`. you expect to bind to an event property that is also called `myClick`.
<code-example path="template-syntax/src/app/app.component.html" region="myClick" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="myClick" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
However, the directive name is often a poor choice for the name of a property within the directive class. However, the directive name is often a poor choice for the name of a property within the directive class.
@ -1808,7 +1808,7 @@ the directive's own `clicks` property.
You can specify the alias for the property name by passing it into the input/output decorator like this: You can specify the alias for the property name by passing it into the input/output decorator like this:
<code-example path="template-syntax/src/app/click.directive.ts" region="output-myClick" title="src/app/click.directive.ts" linenums="false"> <code-example path="template-syntax/src/app/click.directive.ts" region="output-myClick" header="src/app/click.directive.ts" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -1817,7 +1817,7 @@ You can also alias property names in the `inputs` and `outputs` arrays.
You write a colon-delimited (`:`) string with You write a colon-delimited (`:`) string with
the directive property name on the *left* and the public alias on the *right*: the directive property name on the *left* and the public alias on the *right*:
<code-example path="template-syntax/src/app/click.directive.ts" region="output-myClick2" title="src/app/click.directive.ts" linenums="false"> <code-example path="template-syntax/src/app/click.directive.ts" region="output-myClick2" header="src/app/click.directive.ts" linenums="false">
</code-example> </code-example>
</div> </div>
@ -1843,24 +1843,24 @@ Angular [pipes](guide/pipes) are a good choice for small transformations such as
Pipes are simple functions that accept an input value and return a transformed value. Pipes are simple functions that accept an input value and return a transformed value.
They're easy to apply within template expressions, using the **pipe operator (`|`)**: They're easy to apply within template expressions, using the **pipe operator (`|`)**:
<code-example path="template-syntax/src/app/app.component.html" region="pipes-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="pipes-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The pipe operator passes the result of an expression on the left to a pipe function on the right. The pipe operator passes the result of an expression on the left to a pipe function on the right.
You can chain expressions through multiple pipes: You can chain expressions through multiple pipes:
<code-example path="template-syntax/src/app/app.component.html" region="pipes-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="pipes-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
And you can also [apply parameters](guide/pipes#parameterizing-a-pipe) to a pipe: And you can also [apply parameters](guide/pipes#parameterizing-a-pipe) to a pipe:
<code-example path="template-syntax/src/app/app.component.html" region="pipes-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="pipes-3" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The `json` pipe is particularly helpful for debugging bindings: The `json` pipe is particularly helpful for debugging bindings:
<code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (pipes-json)" region="pipes-json"> <code-example path="template-syntax/src/app/app.component.html" linenums="false" header="src/app/app.component.html (pipes-json)" region="pipes-json">
</code-example> </code-example>
The generated output would look something like this The generated output would look something like this
@ -1883,12 +1883,12 @@ The Angular **safe navigation operator (`?.`)** is a fluent and convenient way t
guard against null and undefined values in property paths. guard against null and undefined values in property paths.
Here it is, protecting against a view render failure if the `currentHero` is null. Here it is, protecting against a view render failure if the `currentHero` is null.
<code-example path="template-syntax/src/app/app.component.html" region="safe-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="safe-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
What happens when the following data bound `title` property is null? What happens when the following data bound `title` property is null?
<code-example path="template-syntax/src/app/app.component.html" region="safe-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="safe-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The view still renders but the displayed value is blank; you see only "The title is" with nothing after it. The view still renders but the displayed value is blank; you see only "The title is" with nothing after it.
@ -1924,13 +1924,13 @@ Unfortunately, the app crashes when the `currentHero` is null.
You could code around that problem with [*ngIf](guide/template-syntax#ngIf). You could code around that problem with [*ngIf](guide/template-syntax#ngIf).
<code-example path="template-syntax/src/app/app.component.html" region="safe-4" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="safe-4" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You could try to chain parts of the property path with `&&`, knowing that the expression bails out You could try to chain parts of the property path with `&&`, knowing that the expression bails out
when it encounters the first null. when it encounters the first null.
<code-example path="template-syntax/src/app/app.component.html" region="safe-5" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="safe-5" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
These approaches have merit but can be cumbersome, especially if the property path is long. These approaches have merit but can be cumbersome, especially if the property path is long.
@ -1940,7 +1940,7 @@ The Angular safe navigation operator (`?.`) is a more fluent and convenient way
The expression bails out when it hits the first null value. The expression bails out when it hits the first null value.
The display is blank, but the app keeps rolling without errors. The display is blank, but the app keeps rolling without errors.
<code-example path="template-syntax/src/app/app.component.html" region="safe-6" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="safe-6" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
It works perfectly with long property paths such as `a?.b?.c?.d`. It works perfectly with long property paths such as `a?.b?.c?.d`.
@ -1966,7 +1966,7 @@ The _Angular_ **non-null assertion operator (`!`)** serves the same purpose in a
For example, after you use [*ngIf](guide/template-syntax#ngIf) to check that `hero` is defined, you can assert that For example, after you use [*ngIf](guide/template-syntax#ngIf) to check that `hero` is defined, you can assert that
`hero` properties are also defined. `hero` properties are also defined.
<code-example path="template-syntax/src/app/app.component.html" region="non-null-assertion-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="non-null-assertion-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
When the Angular compiler turns your template into TypeScript code, When the Angular compiler turns your template into TypeScript code,
@ -1991,7 +1991,7 @@ Sometimes a binding expression will be reported as a type error and it is not po
to fully specify the type. To silence the error, you can use the `$any` cast function to cast to fully specify the type. To silence the error, you can use the `$any` cast function to cast
the expression to [the `any` type](http://www.typescriptlang.org/docs/handbook/basic-types.html#any). the expression to [the `any` type](http://www.typescriptlang.org/docs/handbook/basic-types.html#any).
<code-example path="template-syntax/src/app/app.component.html" region="any-type-cast-function-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="any-type-cast-function-1" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
In this example, when the Angular compiler turns your template into TypeScript code, In this example, when the Angular compiler turns your template into TypeScript code,
@ -2001,7 +2001,7 @@ interface.
The `$any` cast function can be used in conjunction with `this` to allow access to undeclared members of The `$any` cast function can be used in conjunction with `this` to allow access to undeclared members of
the component. the component.
<code-example path="template-syntax/src/app/app.component.html" region="any-type-cast-function-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="any-type-cast-function-2" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The `$any` cast function can be used anywhere in a binding expression where a method call is valid. The `$any` cast function can be used anywhere in a binding expression where a method call is valid.

View File

@ -278,7 +278,7 @@ Services are often the easiest files to unit test.
Here are some synchronous and asynchronous unit tests of the `ValueService` Here are some synchronous and asynchronous unit tests of the `ValueService`
written without assistance from Angular testing utilities. written without assistance from Angular testing utilities.
<code-example path="testing/src/app/demo/demo.spec.ts" region="ValueService" title="app/demo/demo.spec.ts"></code-example> <code-example path="testing/src/app/demo/demo.spec.ts" region="ValueService" header="app/demo/demo.spec.ts"></code-example>
{@a services-with-dependencies} {@a services-with-dependencies}
@ -290,13 +290,13 @@ calling the service's constructor.
The `MasterService` is a simple example: The `MasterService` is a simple example:
<code-example path="testing/src/app/demo/demo.ts" region="MasterService" title="app/demo/demo.ts" linenums="false"></code-example> <code-example path="testing/src/app/demo/demo.ts" region="MasterService" header="app/demo/demo.ts" linenums="false"></code-example>
`MasterService` delegates its only method, `getValue`, to the injected `ValueService`. `MasterService` delegates its only method, `getValue`, to the injected `ValueService`.
Here are several ways to test it. Here are several ways to test it.
<code-example path="testing/src/app/demo/demo.spec.ts" region="MasterService" title="app/demo/demo.spec.ts"></code-example> <code-example path="testing/src/app/demo/demo.spec.ts" region="MasterService" header="app/demo/demo.spec.ts"></code-example>
The first test creates a `ValueService` with `new` and passes it to the `MasterService` constructor. The first test creates a `ValueService` with `new` and passes it to the `MasterService` constructor.
@ -348,7 +348,7 @@ array of the services that you'll test or mock.
<code-example <code-example
path="testing/src/app/demo/demo.testbed.spec.ts" path="testing/src/app/demo/demo.testbed.spec.ts"
region="value-service-before-each" region="value-service-before-each"
title="app/demo/demo.testbed.spec.ts (provide ValueService in beforeEach"> header="app/demo/demo.testbed.spec.ts (provide ValueService in beforeEach">
</code-example> </code-example>
Then inject it inside a test by calling `TestBed.get()` with the service class as the argument. Then inject it inside a test by calling `TestBed.get()` with the service class as the argument.
@ -396,7 +396,7 @@ Begin by putting re-usable, preparatory code in a _setup_ function instead of `b
<code-example <code-example
path="testing/src/app/demo/demo.spec.ts" path="testing/src/app/demo/demo.spec.ts"
region="no-before-each-setup" region="no-before-each-setup"
title="app/demo/demo.spec.ts (setup)" linenums="false"> header="app/demo/demo.spec.ts (setup)" linenums="false">
</code-example> </code-example>
The `setup()` function returns an object literal The `setup()` function returns an object literal
@ -439,7 +439,7 @@ test any service with a dependency.
<code-example <code-example
path="testing/src/app/model/hero.service.spec.ts" path="testing/src/app/model/hero.service.spec.ts"
region="test-with-spies" region="test-with-spies"
title="app/model/hero.service.spec.ts (tests with spies)"> header="app/model/hero.service.spec.ts (tests with spies)">
</code-example> </code-example>
<div class="alert is-important"> <div class="alert is-important">
@ -500,7 +500,7 @@ Consider this `LightswitchComponent` which toggles a light on and off
<code-example <code-example
path="testing/src/app/demo/demo.ts" path="testing/src/app/demo/demo.ts"
region="LightswitchComp" region="LightswitchComp"
title="app/demo/demo.ts (LightswitchComp)" linenums="false"> header="app/demo/demo.ts (LightswitchComp)" linenums="false">
</code-example> </code-example>
You might decide only to test that the `clicked()` method You might decide only to test that the `clicked()` method
@ -514,7 +514,7 @@ Do the same with the component class.
<code-example <code-example
path="testing/src/app/demo/demo.spec.ts" path="testing/src/app/demo/demo.spec.ts"
region="Lightswitch" region="Lightswitch"
title="app/demo/demo.spec.ts (Lightswitch tests)" linenums="false"> header="app/demo/demo.spec.ts (Lightswitch tests)" linenums="false">
</code-example> </code-example>
Here is the `DashboardHeroComponent` from the _Tour of Heroes_ tutorial. Here is the `DashboardHeroComponent` from the _Tour of Heroes_ tutorial.
@ -522,7 +522,7 @@ Here is the `DashboardHeroComponent` from the _Tour of Heroes_ tutorial.
<code-example <code-example
path="testing/src/app/dashboard/dashboard-hero.component.ts" path="testing/src/app/dashboard/dashboard-hero.component.ts"
region="class" region="class"
title="app/dashboard/dashboard-hero.component.ts (component)" linenums="false"> header="app/dashboard/dashboard-hero.component.ts (component)" linenums="false">
</code-example> </code-example>
It appears within the template of a parent component, It appears within the template of a parent component,
@ -535,7 +535,7 @@ or its parent component.
<code-example <code-example
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="class-only" region="class-only"
title="app/dashboard/dashboard-hero.component.spec.ts (class tests)" linenums="false"> header="app/dashboard/dashboard-hero.component.spec.ts (class tests)" linenums="false">
</code-example> </code-example>
When a component has dependencies, you may wish to use the `TestBed` to both When a component has dependencies, you may wish to use the `TestBed` to both
@ -546,7 +546,7 @@ The following `WelcomeComponent` depends on the `UserService` to know the name o
<code-example <code-example
path="testing/src/app/welcome/welcome.component.ts" path="testing/src/app/welcome/welcome.component.ts"
region="class" region="class"
title="app/welcome/welcome.component.ts" linenums="false"> header="app/welcome/welcome.component.ts" linenums="false">
</code-example> </code-example>
You might start by creating a mock of the `UserService` that meets the minimum needs of this component. You might start by creating a mock of the `UserService` that meets the minimum needs of this component.
@ -554,7 +554,7 @@ You might start by creating a mock of the `UserService` that meets the minimum n
<code-example <code-example
path="testing/src/app/welcome/welcome.component.spec.ts" path="testing/src/app/welcome/welcome.component.spec.ts"
region="mock-user-service" region="mock-user-service"
title="app/welcome/welcome.component.spec.ts (MockUserService)" linenums="false"> header="app/welcome/welcome.component.spec.ts (MockUserService)" linenums="false">
</code-example> </code-example>
Then provide and inject _both the_ **component** _and the service_ in the `TestBed` configuration. Then provide and inject _both the_ **component** _and the service_ in the `TestBed` configuration.
@ -562,7 +562,7 @@ Then provide and inject _both the_ **component** _and the service_ in the `TestB
<code-example <code-example
path="testing/src/app/welcome/welcome.component.spec.ts" path="testing/src/app/welcome/welcome.component.spec.ts"
region="class-only-before-each" region="class-only-before-each"
title="app/welcome/welcome.component.spec.ts (class-only setup)" linenums="false"> header="app/welcome/welcome.component.spec.ts (class-only setup)" linenums="false">
</code-example> </code-example>
Then exercise the component class, remembering to call the [lifecycle hook methods](guide/lifecycle-hooks) as Angular does when running the app. Then exercise the component class, remembering to call the [lifecycle hook methods](guide/lifecycle-hooks) as Angular does when running the app.
@ -570,7 +570,7 @@ Then exercise the component class, remembering to call the [lifecycle hook metho
<code-example <code-example
path="testing/src/app/welcome/welcome.component.spec.ts" path="testing/src/app/welcome/welcome.component.spec.ts"
region="class-only-tests" region="class-only-tests"
title="app/welcome/welcome.component.spec.ts (class-only tests)" linenums="false"> header="app/welcome/welcome.component.spec.ts (class-only tests)" linenums="false">
</code-example> </code-example>
### Component DOM testing ### Component DOM testing
@ -622,7 +622,7 @@ It also generates an initial test file for the component, `banner-external.compo
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="v1" region="v1"
title="app/banner/banner-external.component.spec.ts (initial)" linenums="false"> header="app/banner/banner-external.component.spec.ts (initial)" linenums="false">
</code-example> </code-example>
#### Reduce the setup #### Reduce the setup
@ -638,7 +638,7 @@ For now, you can radically reduce this test file to a more manageable size:
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="v2" region="v2"
title="app/banner/banner-initial.component.spec.ts (minimal)" linenums="false"> header="app/banner/banner-initial.component.spec.ts (minimal)" linenums="false">
</code-example> </code-example>
In this example, the metadata object passed to `TestBed.configureTestingModule` In this example, the metadata object passed to `TestBed.configureTestingModule`
@ -856,7 +856,7 @@ the component's `title` property like this.
<code-example <code-example
path="testing/src/app/banner/banner.component.ts" path="testing/src/app/banner/banner.component.ts"
region="component" region="component"
title="app/banner/banner.component.ts" linenums="false"> header="app/banner/banner.component.ts" linenums="false">
</code-example> </code-example>
Simple as this is, you decide to add a test to confirm that component Simple as this is, you decide to add a test to confirm that component
@ -873,7 +873,7 @@ and assign it to the `h1` variable.
<code-example <code-example
path="testing/src/app/banner/banner.component.spec.ts" path="testing/src/app/banner/banner.component.spec.ts"
region="setup" region="setup"
title="app/banner/banner.component.spec.ts (setup)" linenums="false"> header="app/banner/banner.component.spec.ts (setup)" linenums="false">
</code-example> </code-example>
{@a detect-changes} {@a detect-changes}
@ -938,15 +938,15 @@ Some testers prefer that the Angular test environment run change detection autom
That's possible by configuring the `TestBed` with the `ComponentFixtureAutoDetect` provider. That's possible by configuring the `TestBed` with the `ComponentFixtureAutoDetect` provider.
First import it from the testing utility library: First import it from the testing utility library:
<code-example path="testing/src/app/banner/banner.component.detect-changes.spec.ts" region="import-ComponentFixtureAutoDetect" title="app/banner/banner.component.detect-changes.spec.ts (import)" linenums="false"></code-example> <code-example path="testing/src/app/banner/banner.component.detect-changes.spec.ts" region="import-ComponentFixtureAutoDetect" header="app/banner/banner.component.detect-changes.spec.ts (import)" linenums="false"></code-example>
Then add it to the `providers` array of the testing module configuration: Then add it to the `providers` array of the testing module configuration:
<code-example path="testing/src/app/banner/banner.component.detect-changes.spec.ts" region="auto-detect" title="app/banner/banner.component.detect-changes.spec.ts (AutoDetect)" linenums="false"></code-example> <code-example path="testing/src/app/banner/banner.component.detect-changes.spec.ts" region="auto-detect" header="app/banner/banner.component.detect-changes.spec.ts (AutoDetect)" linenums="false"></code-example>
Here are three tests that illustrate how automatic change detection works. Here are three tests that illustrate how automatic change detection works.
<code-example path="testing/src/app/banner/banner.component.detect-changes.spec.ts" region="auto-detect-tests" title="app/banner/banner.component.detect-changes.spec.ts (AutoDetect Tests)" linenums="false"></code-example> <code-example path="testing/src/app/banner/banner.component.detect-changes.spec.ts" region="auto-detect-tests" header="app/banner/banner.component.detect-changes.spec.ts (AutoDetect Tests)" linenums="false"></code-example>
The first test shows the benefit of automatic change detection. The first test shows the benefit of automatic change detection.
@ -981,7 +981,7 @@ _Then_ you call `detectChanges()`.
The following example demonstrates the proper sequence. The following example demonstrates the proper sequence.
<code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="title-case-pipe" title="app/hero/hero-detail.component.spec.ts (pipe test)"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="title-case-pipe" header="app/hero/hero-detail.component.spec.ts (pipe test)"></code-example>
<hr> <hr>
@ -996,7 +996,7 @@ as the following variant of `BannerComponent` does.
<code-example <code-example
path="testing/src/app/banner/banner-external.component.ts" path="testing/src/app/banner/banner-external.component.ts"
region="metadata" region="metadata"
title="app/banner/banner-external.component.ts (metadata)" linenums="false"> header="app/banner/banner-external.component.ts (metadata)" linenums="false">
</code-example> </code-example>
This syntax tells the Angular compiler to read the external files during component compilation. This syntax tells the Angular compiler to read the external files during component compilation.
@ -1028,12 +1028,12 @@ Components often have service dependencies.
The `WelcomeComponent` displays a welcome message to the logged in user. The `WelcomeComponent` displays a welcome message to the logged in user.
It knows who the user is based on a property of the injected `UserService`: It knows who the user is based on a property of the injected `UserService`:
<code-example path="testing/src/app/welcome/welcome.component.ts" title="app/welcome/welcome.component.ts" linenums="false"></code-example> <code-example path="testing/src/app/welcome/welcome.component.ts" header="app/welcome/welcome.component.ts" linenums="false"></code-example>
The `WelcomeComponent` has decision logic that interacts with the service, logic that makes this component worth testing. The `WelcomeComponent` has decision logic that interacts with the service, logic that makes this component worth testing.
Here's the testing module configuration for the spec file, `app/welcome/welcome.component.spec.ts`: Here's the testing module configuration for the spec file, `app/welcome/welcome.component.spec.ts`:
<code-example path="testing/src/app/welcome/welcome.component.spec.ts" region="config-test-module" title="app/welcome/welcome.component.spec.ts" linenums="false"></code-example> <code-example path="testing/src/app/welcome/welcome.component.spec.ts" region="config-test-module" header="app/welcome/welcome.component.spec.ts" linenums="false"></code-example>
This time, in addition to declaring the _component-under-test_, This time, in addition to declaring the _component-under-test_,
the configuration adds a `UserService` provider to the `providers` list. the configuration adds a `UserService` provider to the `providers` list.
@ -1060,7 +1060,7 @@ and its tests:
<code-example <code-example
path="testing/src/app/welcome/welcome.component.spec.ts" path="testing/src/app/welcome/welcome.component.spec.ts"
region="user-service-stub" region="user-service-stub"
title="app/welcome/welcome.component.spec.ts" linenums="false"> header="app/welcome/welcome.component.spec.ts" linenums="false">
</code-example> </code-example>
{@a get-injected-service} {@a get-injected-service}
@ -1080,7 +1080,7 @@ The component injector is a property of the fixture's `DebugElement`.
<code-example <code-example
path="testing/src/app/welcome/welcome.component.spec.ts" path="testing/src/app/welcome/welcome.component.spec.ts"
region="injected-service" region="injected-service"
title="WelcomeComponent's injector"> header="WelcomeComponent's injector">
</code-example> </code-example>
{@a testbed-get} {@a testbed-get}
@ -1097,7 +1097,7 @@ so it is safe to call `TestBed.get()` as follows:
<code-example <code-example
path="testing/src/app/welcome/welcome.component.spec.ts" path="testing/src/app/welcome/welcome.component.spec.ts"
region="inject-from-testbed" region="inject-from-testbed"
title="TestBed injector"> header="TestBed injector">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -1118,7 +1118,7 @@ that's provided to the testing module in the body of your test.
The `userService` instance injected into the component is a completely _different_ object, The `userService` instance injected into the component is a completely _different_ object,
a clone of the provided `userServiceStub`. a clone of the provided `userServiceStub`.
<code-example path="testing/src/app/welcome/welcome.component.spec.ts" region="stub-not-injected" title="app/welcome/welcome.component.spec.ts" linenums="false"></code-example> <code-example path="testing/src/app/welcome/welcome.component.spec.ts" region="stub-not-injected" header="app/welcome/welcome.component.spec.ts" linenums="false"></code-example>
{@a welcome-spec-setup} {@a welcome-spec-setup}
@ -1126,11 +1126,11 @@ a clone of the provided `userServiceStub`.
Here's the complete `beforeEach()`, using `TestBed.get()`: Here's the complete `beforeEach()`, using `TestBed.get()`:
<code-example path="testing/src/app/welcome/welcome.component.spec.ts" region="setup" title="app/welcome/welcome.component.spec.ts" linenums="false"></code-example> <code-example path="testing/src/app/welcome/welcome.component.spec.ts" region="setup" header="app/welcome/welcome.component.spec.ts" linenums="false"></code-example>
And here are some tests: And here are some tests:
<code-example path="testing/src/app/welcome/welcome.component.spec.ts" region="tests" title="app/welcome/welcome.component.spec.ts" linenums="false"></code-example> <code-example path="testing/src/app/welcome/welcome.component.spec.ts" region="tests" header="app/welcome/welcome.component.spec.ts" linenums="false"></code-example>
The first is a sanity test; it confirms that the stubbed `UserService` is called and working. The first is a sanity test; it confirms that the stubbed `UserService` is called and working.
@ -1158,7 +1158,7 @@ The `TwainComponent` displays Mark Twain quotes.
<code-example <code-example
path="testing/src/app/twain/twain.component.ts" path="testing/src/app/twain/twain.component.ts"
region="template" region="template"
title="app/twain/twain.component.ts (template)" linenums="false"> header="app/twain/twain.component.ts (template)" linenums="false">
</code-example> </code-example>
Note that value of the component's `quote` property passes through an `AsyncPipe`. Note that value of the component's `quote` property passes through an `AsyncPipe`.
@ -1170,7 +1170,7 @@ the `quote` property returns an `Observable`.
<code-example <code-example
path="testing/src/app/twain/twain.component.ts" path="testing/src/app/twain/twain.component.ts"
region="get-quote" region="get-quote"
title="app/twain/twain.component.ts (getQuote)" linenums="false"> header="app/twain/twain.component.ts (getQuote)" linenums="false">
</code-example> </code-example>
The `TwainComponent` gets quotes from an injected `TwainService`. The `TwainComponent` gets quotes from an injected `TwainService`.
@ -1193,7 +1193,7 @@ They should emulate such calls. The setup in this `app/twain/twain.component.spe
<code-example <code-example
path="testing/src/app/twain/twain.component.spec.ts" path="testing/src/app/twain/twain.component.spec.ts"
region="setup" region="setup"
title="app/twain/twain.component.spec.ts (setup)" linenums="false"> header="app/twain/twain.component.spec.ts (setup)" linenums="false">
</code-example> </code-example>
{@a service-spy} {@a service-spy}
@ -1326,11 +1326,11 @@ If you run other `macroTask` such as `HTMLCanvasElement.toBlob()`, `Unknown macr
<code-tabs> <code-tabs>
<code-pane <code-pane
path="testing/src/app/shared/canvas.component.spec.ts" path="testing/src/app/shared/canvas.component.spec.ts"
title="src/app/shared/canvas.component.spec.ts" linenums="false"> header="src/app/shared/canvas.component.spec.ts" linenums="false">
</code-pane> </code-pane>
<code-pane <code-pane
path="testing/src/app/shared/canvas.component.ts" path="testing/src/app/shared/canvas.component.ts"
title="src/app/shared/canvas.component.ts" linenums="false"> header="src/app/shared/canvas.component.ts" linenums="false">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -1385,7 +1385,7 @@ Or you can copy this one from the sample code.
<code-example <code-example
path="testing/src/testing/async-observable-helpers.ts" path="testing/src/testing/async-observable-helpers.ts"
region="async-data" region="async-data"
title="testing/async-observable-helpers.ts"> header="testing/async-observable-helpers.ts">
</code-example> </code-example>
This helper's observable emits the `data` value in the next turn of the JavaScript engine. This helper's observable emits the `data` value in the next turn of the JavaScript engine.
@ -1548,7 +1548,7 @@ Then import the symbols you need.
<code-example <code-example
path="testing/src/app/twain/twain.component.marbles.spec.ts" path="testing/src/app/twain/twain.component.marbles.spec.ts"
region="import-marbles" region="import-marbles"
title="app/twain/twain.component.marbles.spec.ts (import marbles)" linenums="false"> header="app/twain/twain.component.marbles.spec.ts (import marbles)" linenums="false">
</code-example> </code-example>
Here's the complete test for getting a quote: Here's the complete test for getting a quote:
@ -1652,7 +1652,7 @@ The `DashboardHeroComponent` is embedded in the `DashboardComponent` template li
<code-example <code-example
path="testing/src/app/dashboard/dashboard.component.html" path="testing/src/app/dashboard/dashboard.component.html"
region="dashboard-hero" region="dashboard-hero"
title="app/dashboard/dashboard.component.html (excerpt)" linenums="false"> header="app/dashboard/dashboard.component.html (excerpt)" linenums="false">
</code-example> </code-example>
The `DashboardHeroComponent` appears in an `*ngFor` repeater, which sets each component's `hero` input property The `DashboardHeroComponent` appears in an `*ngFor` repeater, which sets each component's `hero` input property
@ -1665,7 +1665,7 @@ Here's the component's full definition:
<code-example <code-example
path="testing/src/app/dashboard/dashboard-hero.component.ts" path="testing/src/app/dashboard/dashboard-hero.component.ts"
region="component" region="component"
title="app/dashboard/dashboard-hero.component.ts (component)" linenums="false"> header="app/dashboard/dashboard-hero.component.ts (component)" linenums="false">
</code-example> </code-example>
While testing a component this simple has little intrinsic value, it's worth knowing how. While testing a component this simple has little intrinsic value, it's worth knowing how.
@ -1680,7 +1680,7 @@ A quick look at the `DashboardComponent` constructor discourages the first appro
<code-example <code-example
path="testing/src/app/dashboard/dashboard.component.ts" path="testing/src/app/dashboard/dashboard.component.ts"
region="ctor" region="ctor"
title="app/dashboard/dashboard.component.ts (constructor)" linenums="false"> header="app/dashboard/dashboard.component.ts (constructor)" linenums="false">
</code-example> </code-example>
The `DashboardComponent` depends on the Angular router and the `HeroService`. The `DashboardComponent` depends on the Angular router and the `HeroService`.
@ -1705,7 +1705,7 @@ Here's the meat of the spec file setup.
<code-example <code-example
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="setup" region="setup"
title="app/dashboard/dashboard-hero.component.spec.ts (setup)" linenums="false"> header="app/dashboard/dashboard-hero.component.spec.ts (setup)" linenums="false">
</code-example> </code-example>
Note how the setup code assigns a test hero (`expectedHero`) to the component's `hero` property, Note how the setup code assigns a test hero (`expectedHero`) to the component's `hero` property,
@ -1804,7 +1804,7 @@ in a helper such as the `click()` function below:
<code-example <code-example
path="testing/src/testing/index.ts" path="testing/src/testing/index.ts"
region="click-event" region="click-event"
title="testing/index.ts (click helper)" linenums="false"> header="testing/index.ts (click helper)" linenums="false">
</code-example> </code-example>
The first parameter is the _element-to-click_. If you wish, you can pass a The first parameter is the _element-to-click_. If you wish, you can pass a
@ -1826,7 +1826,7 @@ Here's the previous test, rewritten using the click helper.
<code-example <code-example
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="click-test-3" region="click-test-3"
title="app/dashboard/dashboard-hero.component.spec.ts (test with click helper)"> header="app/dashboard/dashboard-hero.component.spec.ts (test with click helper)">
</code-example> </code-example>
<hr> <hr>
@ -1851,7 +1851,7 @@ that can be made satisfactorily with a _test host_ like this one:
<code-example <code-example
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="test-host" region="test-host"
title="app/dashboard/dashboard-hero.component.spec.ts (test host)" header="app/dashboard/dashboard-hero.component.spec.ts (test host)"
linenums="false"> linenums="false">
</code-example> </code-example>
@ -1867,7 +1867,7 @@ Later, the tests will be able to easily check `selectedHero` to verify that the
The setup for the _test-host_ tests is similar to the setup for the stand-alone tests: The setup for the _test-host_ tests is similar to the setup for the stand-alone tests:
<code-example path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" region="test-host-setup" title="app/dashboard/dashboard-hero.component.spec.ts (test host setup)" linenums="false"></code-example> <code-example path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" region="test-host-setup" header="app/dashboard/dashboard-hero.component.spec.ts (test host setup)" linenums="false"></code-example>
This testing module configuration shows three important differences: This testing module configuration shows three important differences:
@ -1887,7 +1887,7 @@ The tests themselves are almost identical to the stand-alone version:
<code-example <code-example
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="test-host-tests" region="test-host-tests"
title="app/dashboard/dashboard-hero.component.spec.ts (test-host)" linenums="false"> header="app/dashboard/dashboard-hero.component.spec.ts (test-host)" linenums="false">
</code-example> </code-example>
Only the selected event test differs. It confirms that the selected `DashboardHeroComponent` hero Only the selected event test differs. It confirms that the selected `DashboardHeroComponent` hero
@ -1910,7 +1910,7 @@ which it injects together with the `HeroService`.
<code-example <code-example
path="testing/src/app/dashboard/dashboard.component.ts" path="testing/src/app/dashboard/dashboard.component.ts"
region="ctor" region="ctor"
title="app/dashboard/dashboard.component.ts (constructor)" linenums="false"> header="app/dashboard/dashboard.component.ts (constructor)" linenums="false">
</code-example> </code-example>
Mocking the `HeroService` with a spy is a [familiar story](#component-with-async-service). Mocking the `HeroService` with a spy is a [familiar story](#component-with-async-service).
@ -1921,7 +1921,7 @@ Fortunately, not in this case because the `DashboardComponent` isn't doing much
<code-example <code-example
path="testing/src/app/dashboard/dashboard.component.ts" path="testing/src/app/dashboard/dashboard.component.ts"
region="goto-detail" region="goto-detail"
title="app/dashboard/dashboard.component.ts (goToDetail)"> header="app/dashboard/dashboard.component.ts (goToDetail)">
</code-example> </code-example>
This is often the case with _routing components_. This is often the case with _routing components_.
@ -1934,7 +1934,7 @@ as providing a `HeroService` spy.
<code-example <code-example
path="testing/src/app/dashboard/dashboard.component.spec.ts" path="testing/src/app/dashboard/dashboard.component.spec.ts"
region="router-spy" region="router-spy"
title="app/dashboard/dashboard.component.spec.ts (spies)" linenums="false"> header="app/dashboard/dashboard.component.spec.ts (spies)" linenums="false">
</code-example> </code-example>
The following test clicks the displayed hero and confirms that The following test clicks the displayed hero and confirms that
@ -1943,7 +1943,7 @@ The following test clicks the displayed hero and confirms that
<code-example <code-example
path="testing/src/app/dashboard/dashboard.component.spec.ts" path="testing/src/app/dashboard/dashboard.component.spec.ts"
region="navigate-test" region="navigate-test"
title="app/dashboard/dashboard.component.spec.ts (navigate test)" linenums="false"> header="app/dashboard/dashboard.component.spec.ts (navigate test)" linenums="false">
</code-example> </code-example>
{@a routed-component-w-param} {@a routed-component-w-param}
@ -1964,7 +1964,7 @@ injects it into a new instance of the `HeroDetailComponent`.
Here's the `HeroDetailComponent` constructor: Here's the `HeroDetailComponent` constructor:
<code-example path="testing/src/app/hero/hero-detail.component.ts" region="ctor" title="app/hero/hero-detail.component.ts (constructor)" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.ts" region="ctor" header="app/hero/hero-detail.component.ts (constructor)" linenums="false"></code-example>
The `HeroDetail` component needs the `id` parameter so it can fetch The `HeroDetail` component needs the `id` parameter so it can fetch
the corresponding hero via the `HeroDetailService`. the corresponding hero via the `HeroDetailService`.
@ -1975,7 +1975,7 @@ It can't just reference the `id` property of the `ActivatedRoute.paramMap`.
The component has to _subscribe_ to the `ActivatedRoute.paramMap` observable and be prepared The component has to _subscribe_ to the `ActivatedRoute.paramMap` observable and be prepared
for the `id` to change during its lifetime. for the `id` to change during its lifetime.
<code-example path="testing/src/app/hero/hero-detail.component.ts" region="ng-on-init" title="app/hero/hero-detail.component.ts (ngOnInit)" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.ts" region="ng-on-init" header="app/hero/hero-detail.component.ts (ngOnInit)" linenums="false"></code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -2004,7 +2004,7 @@ The following `ActivatedRouteStub` class serves as a test double for `ActivatedR
<code-example <code-example
path="testing/src/testing/activated-route-stub.ts" path="testing/src/testing/activated-route-stub.ts"
region="activated-route-stub" region="activated-route-stub"
title="testing/activated-route-stub.ts (ActivatedRouteStub)" linenums="false"> header="testing/activated-route-stub.ts (ActivatedRouteStub)" linenums="false">
</code-example> </code-example>
Consider placing such helpers in a `testing` folder sibling to the `app` folder. Consider placing such helpers in a `testing` folder sibling to the `app` folder.
@ -2023,7 +2023,7 @@ the [_marble testing library_](#marble-testing).
Here's a test demonstrating the component's behavior when the observed `id` refers to an existing hero: Here's a test demonstrating the component's behavior when the observed `id` refers to an existing hero:
<code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="route-good-id" title="app/hero/hero-detail.component.spec.ts (existing id)" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="route-good-id" header="app/hero/hero-detail.component.spec.ts (existing id)" linenums="false"></code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -2038,7 +2038,7 @@ The test suite setup provided the same router spy [described above](#routing-com
This test expects the component to try to navigate to the `HeroListComponent`. This test expects the component to try to navigate to the `HeroListComponent`.
<code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="route-bad-id" title="app/hero/hero-detail.component.spec.ts (bad id)" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="route-bad-id" header="app/hero/hero-detail.component.spec.ts (bad id)" linenums="false"></code-example>
While this app doesn't have a route to the `HeroDetailComponent` that omits the `id` parameter, it might add such a route someday. While this app doesn't have a route to the `HeroDetailComponent` that omits the `id` parameter, it might add such a route someday.
The component should do something reasonable when there is no `id`. The component should do something reasonable when there is no `id`.
@ -2049,7 +2049,7 @@ New heroes have `id=0` and a blank `name`. This test confirms that the component
<code-example <code-example
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="route-no-id" region="route-no-id"
title="app/hero/hero-detail.component.spec.ts (no id)" linenums="false"> header="app/hero/hero-detail.component.spec.ts (no id)" linenums="false">
</code-example> </code-example>
<hr> <hr>
@ -2066,7 +2066,7 @@ The `AppComponent`, for example, displays a navigation bar with anchors and thei
<code-example <code-example
path="testing/src/app/app.component.html" path="testing/src/app/app.component.html"
title="app/app.component.html" linenums="false"> header="app/app.component.html" linenums="false">
</code-example> </code-example>
While the `AppComponent` _class_ is empty, While the `AppComponent` _class_ is empty,
@ -2105,7 +2105,7 @@ and directive that play little or no role in the tests.
<code-example <code-example
path="testing/src/app/app.component.spec.ts" path="testing/src/app/app.component.spec.ts"
region="component-stubs" region="component-stubs"
title="app/app.component.spec.ts (stub declaration)" linenums="false"> header="app/app.component.spec.ts (stub declaration)" linenums="false">
</code-example> </code-example>
The stub selectors match the selectors for the corresponding real components. The stub selectors match the selectors for the corresponding real components.
@ -2117,7 +2117,7 @@ components, directives, and pipes that need to be real.
<code-example <code-example
path="testing/src/app/app.component.spec.ts" path="testing/src/app/app.component.spec.ts"
region="testbed-stubs" region="testbed-stubs"
title="app/app.component.spec.ts (TestBed stubs)" linenums="false"> header="app/app.component.spec.ts (TestBed stubs)" linenums="false">
</code-example> </code-example>
The `AppComponent` is the test subject, so of course you declare the real version. The `AppComponent` is the test subject, so of course you declare the real version.
@ -2136,7 +2136,7 @@ In the second approach, add `NO_ERRORS_SCHEMA` to the `TestBed.schemas` metadata
<code-example <code-example
path="testing/src/app/app.component.spec.ts" path="testing/src/app/app.component.spec.ts"
region="no-errors-schema" region="no-errors-schema"
title="app/app.component.spec.ts (NO_ERRORS_SCHEMA)" linenums="false"> header="app/app.component.spec.ts (NO_ERRORS_SCHEMA)" linenums="false">
</code-example> </code-example>
The `NO_ERRORS_SCHEMA` tells the Angular compiler to ignore unrecognized elements and attributes. The `NO_ERRORS_SCHEMA` tells the Angular compiler to ignore unrecognized elements and attributes.
@ -2173,7 +2173,7 @@ as seen in this example.
<code-example <code-example
path="testing/src/app/app.component.spec.ts" path="testing/src/app/app.component.spec.ts"
region="mixed-setup" region="mixed-setup"
title="app/app.component.spec.ts (mixed setup)" linenums="false"> header="app/app.component.spec.ts (mixed setup)" linenums="false">
</code-example> </code-example>
The Angular compiler creates the `BannerComponentStub` for the `<app-banner>` element The Angular compiler creates the `BannerComponentStub` for the `<app-banner>` element
@ -2196,7 +2196,7 @@ seen in the `AppComponent` template.
<code-example <code-example
path="testing/src/testing/router-link-directive-stub.ts" path="testing/src/testing/router-link-directive-stub.ts"
region="router-link" region="router-link"
title="testing/router-link-directive-stub.ts (RouterLinkDirectiveStub)" linenums="false"> header="testing/router-link-directive-stub.ts (RouterLinkDirectiveStub)" linenums="false">
</code-example> </code-example>
The URL bound to the `[routerLink]` attribute flows in to the directive's `linkParams` property. The URL bound to the `[routerLink]` attribute flows in to the directive's `linkParams` property.
@ -2226,7 +2226,7 @@ A little more setup triggers the initial data binding and gets references to the
<code-example <code-example
path="testing/src/app/app.component.spec.ts" path="testing/src/app/app.component.spec.ts"
region="test-setup" region="test-setup"
title="app/app.component.spec.ts (test setup)" linenums="false"> header="app/app.component.spec.ts (test setup)" linenums="false">
</code-example> </code-example>
Three points of special interest: Three points of special interest:
@ -2243,7 +2243,7 @@ The `AppComponent` links to validate are as follows:
<code-example <code-example
path="testing/src/app/app.component.html" path="testing/src/app/app.component.html"
region="links" region="links"
title="app/app.component.html (navigation links)" linenums="false"> header="app/app.component.html (navigation links)" linenums="false">
</code-example> </code-example>
{@a app-component-tests} {@a app-component-tests}
@ -2251,7 +2251,7 @@ The `AppComponent` links to validate are as follows:
Here are some tests that confirm those links are wired to the `routerLink` directives Here are some tests that confirm those links are wired to the `routerLink` directives
as expected: as expected:
<code-example path="testing/src/app/app.component.spec.ts" region="tests" title="app/app.component.spec.ts (selected tests)" linenums="false"></code-example> <code-example path="testing/src/app/app.component.spec.ts" region="tests" header="app/app.component.spec.ts (selected tests)" linenums="false"></code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -2306,7 +2306,7 @@ The `HeroDetailComponent` is a simple view with a title, two hero fields, and tw
But there's plenty of template complexity even in this simple form. But there's plenty of template complexity even in this simple form.
<code-example <code-example
path="testing/src/app/hero/hero-detail.component.html" title="app/hero/hero-detail.component.html" linenums="false"> path="testing/src/app/hero/hero-detail.component.html" header="app/hero/hero-detail.component.html" linenums="false">
</code-example> </code-example>
Tests that exercise the component need ... Tests that exercise the component need ...
@ -2327,7 +2327,7 @@ Here is such a `Page` class for the `hero-detail.component.spec.ts`
<code-example <code-example
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="page" region="page"
title="app/hero/hero-detail.component.spec.ts (Page)" linenums="false"> header="app/hero/hero-detail.component.spec.ts (Page)" linenums="false">
</code-example> </code-example>
Now the important hooks for component manipulation and inspection are neatly organized and accessible from an instance of `Page`. Now the important hooks for component manipulation and inspection are neatly organized and accessible from an instance of `Page`.
@ -2337,7 +2337,7 @@ A `createComponent` method creates a `page` object and fills in the blanks once
<code-example <code-example
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="create-component" region="create-component"
title="app/hero/hero-detail.component.spec.ts (createComponent)" linenums="false"> header="app/hero/hero-detail.component.spec.ts (createComponent)" linenums="false">
</code-example> </code-example>
The [_HeroDetailComponent_ tests](#tests-w-test-double) in an earlier section demonstrate how `createComponent` and `page` The [_HeroDetailComponent_ tests](#tests-w-test-double) in an earlier section demonstrate how `createComponent` and `page`
@ -2349,7 +2349,7 @@ Here are a few more `HeroDetailComponent` tests to reinforce the point.
<code-example <code-example
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="selected-tests" region="selected-tests"
title="app/hero/hero-detail.component.spec.ts (selected tests)" linenums="false"> header="app/hero/hero-detail.component.spec.ts (selected tests)" linenums="false">
</code-example> </code-example>
<hr> <hr>
@ -2377,7 +2377,7 @@ the following version of the `BannerComponent` does.
<code-example <code-example
path="testing/src/app/banner/banner-external.component.ts" path="testing/src/app/banner/banner-external.component.ts"
title="app/banner/banner-external.component.ts (external template & css)" linenums="false"> header="app/banner/banner-external.component.ts (external template & css)" linenums="false">
</code-example> </code-example>
The test fails when the `TestBed` tries to create the component. The test fails when the `TestBed` tries to create the component.
@ -2385,7 +2385,7 @@ The test fails when the `TestBed` tries to create the component.
<code-example <code-example
path="testing/src/app/banner/banner.component.spec.ts" path="testing/src/app/banner/banner.component.spec.ts"
region="configure-and-create" region="configure-and-create"
title="app/banner/banner.component.spec.ts (setup that fails)" header="app/banner/banner.component.spec.ts (setup that fails)"
avoid linenums="false"> avoid linenums="false">
</code-example> </code-example>
@ -2437,7 +2437,7 @@ Write the first async `beforeEach` like this.
<code-example <code-example
path="testing/src/app/banner/banner-external.component.spec.ts" path="testing/src/app/banner/banner-external.component.spec.ts"
region="async-before-each" region="async-before-each"
title="app/banner/banner-external.component.spec.ts (async beforeEach)" linenums="false"> header="app/banner/banner-external.component.spec.ts (async beforeEach)" linenums="false">
</code-example> </code-example>
The `async()` helper function takes a parameterless function with the body of the setup. The `async()` helper function takes a parameterless function with the body of the setup.
@ -2473,7 +2473,7 @@ which include creating the component and querying for elements to inspect.
<code-example <code-example
path="testing/src/app/banner/banner-external.component.spec.ts" path="testing/src/app/banner/banner-external.component.spec.ts"
region="sync-before-each" region="sync-before-each"
title="app/banner/banner-external.component.spec.ts (synchronous beforeEach)" linenums="false"> header="app/banner/banner-external.component.spec.ts (synchronous beforeEach)" linenums="false">
</code-example> </code-example>
You can count on the test runner to wait for the first asynchronous `beforeEach` to finish before calling the second. You can count on the test runner to wait for the first asynchronous `beforeEach` to finish before calling the second.
@ -2489,7 +2489,7 @@ into a `then(...)` callback.
<code-example <code-example
path="testing/src/app/banner/banner-external.component.spec.ts" path="testing/src/app/banner/banner-external.component.spec.ts"
region="one-before-each" region="one-before-each"
title="app/banner/banner-external.component.spec.ts (one beforeEach)" linenums="false"> header="app/banner/banner-external.component.spec.ts (one beforeEach)" linenums="false">
</code-example> </code-example>
#### _compileComponents()_ is harmless #### _compileComponents()_ is harmless
@ -2512,7 +2512,7 @@ Earlier component tests configured the testing module with a few `declarations`
<code-example <code-example
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="config-testbed" region="config-testbed"
title="app/dashboard/dashboard-hero.component.spec.ts (configure TestBed)"> header="app/dashboard/dashboard-hero.component.spec.ts (configure TestBed)">
</code-example> </code-example>
The `DashboardComponent` is simple. It needs no help. The `DashboardComponent` is simple. It needs no help.
@ -2536,7 +2536,7 @@ One approach is to configure the testing module from the individual pieces as in
<code-example <code-example
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="setup-forms-module" region="setup-forms-module"
title="app/hero/hero-detail.component.spec.ts (FormsModule setup)" linenums="false"> header="app/hero/hero-detail.component.spec.ts (FormsModule setup)" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -2560,7 +2560,7 @@ The test configuration can use the `SharedModule` too as seen in this alternativ
<code-example <code-example
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="setup-shared-module" region="setup-shared-module"
title="app/hero/hero-detail.component.spec.ts (SharedModule setup)" linenums="false"> header="app/hero/hero-detail.component.spec.ts (SharedModule setup)" linenums="false">
</code-example> </code-example>
It's a bit tighter and smaller, with fewer import statements (not shown). It's a bit tighter and smaller, with fewer import statements (not shown).
@ -2573,7 +2573,7 @@ The `HeroDetailComponent` is part of the `HeroModule` [Feature Module](guide/fea
including the `SharedModule`. including the `SharedModule`.
Try a test configuration that imports the `HeroModule` like this one: Try a test configuration that imports the `HeroModule` like this one:
<code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="setup-hero-module" title="app/hero/hero-detail.component.spec.ts (HeroModule setup)" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="setup-hero-module" header="app/hero/hero-detail.component.spec.ts (HeroModule setup)" linenums="false"></code-example>
That's _really_ crisp. Only the _test doubles_ in the `providers` remain. Even the `HeroDetailComponent` declaration is gone. That's _really_ crisp. Only the _test doubles_ in the `providers` remain. Even the `HeroDetailComponent` declaration is gone.
@ -2597,7 +2597,7 @@ the module is small, as feature modules tend to be.
The `HeroDetailComponent` provides its own `HeroDetailService`. The `HeroDetailComponent` provides its own `HeroDetailService`.
<code-example path="testing/src/app/hero/hero-detail.component.ts" region="prototype" title="app/hero/hero-detail.component.ts (prototype)" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.ts" region="prototype" header="app/hero/hero-detail.component.ts (prototype)" linenums="false"></code-example>
It's not possible to stub the component's `HeroDetailService` in the `providers` of the `TestBed.configureTestingModule`. It's not possible to stub the component's `HeroDetailService` in the `providers` of the `TestBed.configureTestingModule`.
Those are providers for the _testing module_, not the component. They prepare the dependency injector at the _fixture level_. Those are providers for the _testing module_, not the component. They prepare the dependency injector at the _fixture level_.
@ -2617,7 +2617,7 @@ There might not be a remote server to call.
Fortunately, the `HeroDetailService` delegates responsibility for remote data access to an injected `HeroService`. Fortunately, the `HeroDetailService` delegates responsibility for remote data access to an injected `HeroService`.
<code-example path="testing/src/app/hero/hero-detail.service.ts" region="prototype" title="app/hero/hero-detail.service.ts (prototype)" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-detail.service.ts" region="prototype" header="app/hero/hero-detail.service.ts (prototype)" linenums="false"></code-example>
The [previous test configuration](#feature-module-import) replaces the real `HeroService` with a `TestHeroService` The [previous test configuration](#feature-module-import) replaces the real `HeroService` with a `TestHeroService`
that intercepts server requests and fakes their responses. that intercepts server requests and fakes their responses.
@ -2630,7 +2630,7 @@ What if `HeroDetailService` makes its own server requests?
The `TestBed.overrideComponent` method can replace the component's `providers` with easy-to-manage _test doubles_ The `TestBed.overrideComponent` method can replace the component's `providers` with easy-to-manage _test doubles_
as seen in the following setup variation: as seen in the following setup variation:
<code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="setup-override" title="app/hero/hero-detail.component.spec.ts (Override setup)" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="setup-override" header="app/hero/hero-detail.component.spec.ts (Override setup)" linenums="false"></code-example>
Notice that `TestBed.configureTestingModule` no longer provides a (fake) `HeroService` because it's [not needed](#spy-stub). Notice that `TestBed.configureTestingModule` no longer provides a (fake) `HeroService` because it's [not needed](#spy-stub).
@ -2640,7 +2640,7 @@ Notice that `TestBed.configureTestingModule` no longer provides a (fake) `HeroSe
Focus on the `overrideComponent` method. Focus on the `overrideComponent` method.
<code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="override-component-method" title="app/hero/hero-detail.component.spec.ts (overrideComponent)" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="override-component-method" header="app/hero/hero-detail.component.spec.ts (overrideComponent)" linenums="false"></code-example>
It takes two arguments: the component type to override (`HeroDetailComponent`) and an override metadata object. It takes two arguments: the component type to override (`HeroDetailComponent`) and an override metadata object.
The [override metadata object](#metadata-override-object) is a generic defined as follows: The [override metadata object](#metadata-override-object) is a generic defined as follows:
@ -2681,7 +2681,7 @@ The related `HeroDetailComponent` tests will assert that methods of the `HeroDet
were called by spying on the service methods. were called by spying on the service methods.
Accordingly, the stub implements its methods as spies: Accordingly, the stub implements its methods as spies:
<code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="hds-spy" title="app/hero/hero-detail.component.spec.ts (HeroDetailServiceSpy)" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="hds-spy" header="app/hero/hero-detail.component.spec.ts (HeroDetailServiceSpy)" linenums="false"></code-example>
{@a override-tests} {@a override-tests}
@ -2690,7 +2690,7 @@ Accordingly, the stub implements its methods as spies:
Now the tests can control the component's hero directly by manipulating the spy-stub's `testHero` Now the tests can control the component's hero directly by manipulating the spy-stub's `testHero`
and confirm that service methods were called. and confirm that service methods were called.
<code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="override-tests" title="app/hero/hero-detail.component.spec.ts (override tests)" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="override-tests" header="app/hero/hero-detail.component.spec.ts (override tests)" linenums="false"></code-example>
{@a more-overrides} {@a more-overrides}
@ -2716,16 +2716,16 @@ based on either a data bound color or a default color (lightgray).
It also sets a custom property of the element (`customProperty`) to `true` It also sets a custom property of the element (`customProperty`) to `true`
for no reason other than to show that it can. for no reason other than to show that it can.
<code-example path="testing/src/app/shared/highlight.directive.ts" title="app/shared/highlight.directive.ts" linenums="false"></code-example> <code-example path="testing/src/app/shared/highlight.directive.ts" header="app/shared/highlight.directive.ts" linenums="false"></code-example>
It's used throughout the application, perhaps most simply in the `AboutComponent`: It's used throughout the application, perhaps most simply in the `AboutComponent`:
<code-example path="testing/src/app/about/about.component.ts" title="app/about/about.component.ts" linenums="false"></code-example> <code-example path="testing/src/app/about/about.component.ts" header="app/about/about.component.ts" linenums="false"></code-example>
Testing the specific use of the `HighlightDirective` within the `AboutComponent` requires only the Testing the specific use of the `HighlightDirective` within the `AboutComponent` requires only the
techniques explored above (in particular the ["Shallow test"](#nested-component-tests) approach). techniques explored above (in particular the ["Shallow test"](#nested-component-tests) approach).
<code-example path="testing/src/app/about/about.component.spec.ts" region="tests" title="app/about/about.component.spec.ts" linenums="false"></code-example> <code-example path="testing/src/app/about/about.component.spec.ts" region="tests" header="app/about/about.component.spec.ts" linenums="false"></code-example>
However, testing a single use case is unlikely to explore the full range of a directive's capabilities. However, testing a single use case is unlikely to explore the full range of a directive's capabilities.
Finding and testing all components that use the directive is tedious, brittle, and almost as unlikely to afford full coverage. Finding and testing all components that use the directive is tedious, brittle, and almost as unlikely to afford full coverage.
@ -2737,7 +2737,7 @@ do not inspire confidence in the directive's efficacy.
A better solution is to create an artificial test component that demonstrates all ways to apply the directive. A better solution is to create an artificial test component that demonstrates all ways to apply the directive.
<code-example path="testing/src/app/shared/highlight.directive.spec.ts" region="test-component" title="app/shared/highlight.directive.spec.ts (TestComponent)" linenums="false"></code-example> <code-example path="testing/src/app/shared/highlight.directive.spec.ts" region="test-component" header="app/shared/highlight.directive.spec.ts (TestComponent)" linenums="false"></code-example>
<figure> <figure>
<img src='generated/images/guide/testing/highlight-directive-spec.png' alt="HighlightDirective spec in action"> <img src='generated/images/guide/testing/highlight-directive-spec.png' alt="HighlightDirective spec in action">
@ -2752,7 +2752,7 @@ The initial value is the word "cyan" which should be the background color of the
Here are some tests of this component: Here are some tests of this component:
<code-example path="testing/src/app/shared/highlight.directive.spec.ts" region="selected-tests" title="app/shared/highlight.directive.spec.ts (selected tests)"></code-example> <code-example path="testing/src/app/shared/highlight.directive.spec.ts" region="selected-tests" header="app/shared/highlight.directive.spec.ts (selected tests)"></code-example>
A few techniques are noteworthy: A few techniques are noteworthy:
@ -2786,12 +2786,12 @@ metadata and an interface.
Consider a `TitleCasePipe` that capitalizes the first letter of each word. Consider a `TitleCasePipe` that capitalizes the first letter of each word.
Here's a naive implementation with a regular expression. Here's a naive implementation with a regular expression.
<code-example path="testing/src/app/shared/title-case.pipe.ts" title="app/shared/title-case.pipe.ts" linenums="false"></code-example> <code-example path="testing/src/app/shared/title-case.pipe.ts" header="app/shared/title-case.pipe.ts" linenums="false"></code-example>
Anything that uses a regular expression is worth testing thoroughly. Anything that uses a regular expression is worth testing thoroughly.
Use simple Jasmine to explore the expected cases and the edge cases. Use simple Jasmine to explore the expected cases and the edge cases.
<code-example path="testing/src/app/shared/title-case.pipe.spec.ts" region="excerpt" title="app/shared/title-case.pipe.spec.ts"></code-example> <code-example path="testing/src/app/shared/title-case.pipe.spec.ts" region="excerpt" header="app/shared/title-case.pipe.spec.ts"></code-example>
{@a write-tests} {@a write-tests}
@ -2802,7 +2802,7 @@ They can't tell if the `TitleCasePipe` is working properly as applied in the app
Consider adding component tests such as this one: Consider adding component tests such as this one:
<code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="title-case-pipe" title="app/hero/hero-detail.component.spec.ts (pipe test)"></code-example> <code-example path="testing/src/app/hero/hero-detail.component.spec.ts" region="title-case-pipe" header="app/hero/hero-detail.component.spec.ts (pipe test)"></code-example>
<hr> <hr>
@ -3150,7 +3150,7 @@ Here are the most important static methods, in order of likely utility.
the object to return if Angular can't find the provider the object to return if Angular can't find the provider
(`null` in this example): (`null` in this example):
<code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="testbed-get-w-null" title="app/demo/demo.testbed.spec.ts" linenums="false"></code-example> <code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="testbed-get-w-null" header="app/demo/demo.testbed.spec.ts" linenums="false"></code-example>
After calling `get`, the `TestBed` configuration is frozen for the duration of the current spec. After calling `get`, the `TestBed` configuration is frozen for the duration of the current spec.
@ -3610,7 +3610,7 @@ predicate that filters the source element's subtree for matching `DebugElement`.
The predicate is any method that takes a `DebugElement` and returns a _truthy_ value. The predicate is any method that takes a `DebugElement` and returns a _truthy_ value.
The following example finds all `DebugElements` with a reference to a template local variable named "content": The following example finds all `DebugElements` with a reference to a template local variable named "content":
<code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="custom-predicate" title="app/demo/demo.testbed.spec.ts" linenums="false"></code-example> <code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="custom-predicate" header="app/demo/demo.testbed.spec.ts" linenums="false"></code-example>
The Angular `By` class has three static methods for common predicates: The Angular `By` class has three static methods for common predicates:
@ -3618,7 +3618,7 @@ The Angular `By` class has three static methods for common predicates:
- `By.css(selector)` - return elements with matching CSS selectors. - `By.css(selector)` - return elements with matching CSS selectors.
- `By.directive(directive)` - return elements that Angular matched to an instance of the directive class. - `By.directive(directive)` - return elements that Angular matched to an instance of the directive class.
<code-example path="testing/src/app/hero/hero-list.component.spec.ts" region="by" title="app/hero/hero-list.component.spec.ts" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-list.component.spec.ts" region="by" header="app/hero/hero-list.component.spec.ts" linenums="false"></code-example>
<hr> <hr>

View File

@ -22,12 +22,12 @@ Here's another code sample using the wildcard state together with our previous e
This allows us to add new states without having to include separate transitions for each one. This allows us to add new states without having to include separate transitions for each one.
<code-example title="src/app/open-close.component.ts" path="animations/src/app/open-close.component.ts" region="trigger-wildcard1" language="typescript" linenums="false"> <code-example header="src/app/open-close.component.ts" path="animations/src/app/open-close.component.ts" region="trigger-wildcard1" language="typescript" linenums="false">
</code-example> </code-example>
Use a double arrow syntax to specify state-to-state transitions in both directions. Use a double arrow syntax to specify state-to-state transitions in both directions.
<code-example title="src/app/open-close.component.ts" path="animations/src/app/open-close.component.ts" region="trigger-wildcard2" language="typescript" linenums="false"> <code-example header="src/app/open-close.component.ts" path="animations/src/app/open-close.component.ts" region="trigger-wildcard2" language="typescript" linenums="false">
</code-example> </code-example>
### Using wildcard state with multiple transition states ### Using wildcard state with multiple transition states
@ -39,7 +39,7 @@ In our two-state button example, the wildcard isn't that useful because there ar
</figure> </figure>
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" linenums="false" <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" linenums="false"
region="trigger-transition" language="typescript"> region="trigger-transition" language="typescript">
</code-example> </code-example>
@ -54,7 +54,7 @@ To do this, list the more specific transitions *before* `* => *`.
Use the wildcard `*` with a style to tell the animation to use whatever the current style value is, and animate with that. Wildcard is a fallback value that's used if the state being animated isn't declared within the trigger. Use the wildcard `*` with a style to tell the animation to use whatever the current style value is, and animate with that. Wildcard is a fallback value that's used if the state being animated isn't declared within the trigger.
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" linenums="false" <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" linenums="false"
region="transition4" language="typescript"> region="transition4" language="typescript">
</code-example> </code-example>
@ -88,7 +88,7 @@ Now we'll add a new behavior:
* When you add a hero to the list of heroes, it appears to fly onto the page from the left. * When you add a hero to the list of heroes, it appears to fly onto the page from the left.
* When you remove a hero from the list, it appears to fly out to the right. * When you remove a hero from the list, it appears to fly out to the right.
<code-example path="animations/src/app/hero-list-enter-leave.component.ts" title="src/app/hero-list-enter-leave.component.ts" region="animationdef" language="typescript" linenums="false"> <code-example path="animations/src/app/hero-list-enter-leave.component.ts" header="src/app/hero-list-enter-leave.component.ts" region="animationdef" language="typescript" linenums="false">
</code-example> </code-example>
In the above code, we applied the `void` state when the HTML element isn't attached to a view. In the above code, we applied the `void` state when the HTML element isn't attached to a view.
@ -114,12 +114,12 @@ The `:enter` transition runs when any `*ngIf` or `*ngFor` views are placed on th
In this example, we have a special trigger for the enter and leave animation called `myInsertRemoveTrigger`. The HTML template contains the following code. In this example, we have a special trigger for the enter and leave animation called `myInsertRemoveTrigger`. The HTML template contains the following code.
<code-example path="animations/src/app/insert-remove.component.html" title="src/app/insert-remove.component.html" region="insert-remove" language="typescript"> <code-example path="animations/src/app/insert-remove.component.html" header="src/app/insert-remove.component.html" region="insert-remove" language="typescript">
</code-example> </code-example>
In the component file, the `:enter` transition sets an initial opacity of 0, and then animates it to change that opacity to 1 as the element is inserted into the view. In the component file, the `:enter` transition sets an initial opacity of 0, and then animates it to change that opacity to 1 as the element is inserted into the view.
<code-example path="animations/src/app/insert-remove.component.ts" title="src/app/insert-remove.component.ts" region="enter-leave-trigger" language="typescript"> <code-example path="animations/src/app/insert-remove.component.ts" header="src/app/insert-remove.component.ts" region="enter-leave-trigger" language="typescript">
</code-example> </code-example>
Note that this example doesn't need to use `state()`. Note that this example doesn't need to use `state()`.
@ -134,20 +134,20 @@ The `transition()` function takes additional selector values, `:increment` and `
</div> </div>
<code-example path="animations/src/app/hero-list-page.component.ts" title="src/app/hero-list-page.component.ts" region="increment" language="typescript" linenums="false"></code-example> <code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="increment" language="typescript" linenums="false"></code-example>
## Boolean values in transitions ## Boolean values in transitions
If a trigger contains a boolean value as a binding value, then this value can be matched using a `transition()` expression that compares `true` and `false`, or `1` and `0`. If a trigger contains a boolean value as a binding value, then this value can be matched using a `transition()` expression that compares `true` and `false`, or `1` and `0`.
<code-example path="animations/src/app/open-close.component.2.html" title="src/app/open-close.component.html" region="trigger-boolean"> <code-example path="animations/src/app/open-close.component.2.html" header="src/app/open-close.component.html" region="trigger-boolean">
</code-example> </code-example>
In the code snippet above, the HTML template binds a `<div>` element to a trigger named `openClose` with a status expression of `isOpen`, and with possible values of `true` and `false`. This is an alternative to the practice of creating two named states of `open` and `close`. In the code snippet above, the HTML template binds a `<div>` element to a trigger named `openClose` with a status expression of `isOpen`, and with possible values of `true` and `false`. This is an alternative to the practice of creating two named states of `open` and `close`.
In the component code, in the `@Component` metadata under the `animations:` property, when the state evaluates to `true` (meaning "open" here), the associated HTML element's height is a wildcard style or default. In this case, use whatever height the element already had before the animation started. When the element is "closed," the element animates to a height of 0, which makes it invisible. In the component code, in the `@Component` metadata under the `animations:` property, when the state evaluates to `true` (meaning "open" here), the associated HTML element's height is a wildcard style or default. In this case, use whatever height the element already had before the animation started. When the element is "closed," the element animates to a height of 0, which makes it invisible.
<code-example path="animations/src/app/open-close.component.2.ts" title="src/app/open-close.component.ts" region="trigger-boolean" language="typescript"> <code-example path="animations/src/app/open-close.component.2.ts" header="src/app/open-close.component.ts" region="trigger-boolean" language="typescript">
</code-example> </code-example>
## Multiple animation triggers ## Multiple animation triggers
@ -166,10 +166,10 @@ The code sample below shows how to use this feature.
<code-tabs> <code-tabs>
<code-pane path="animations/src/app/open-close.component.4.html" title="src/app/open-close.component.html" region="toggle-animation"> <code-pane path="animations/src/app/open-close.component.4.html" header="src/app/open-close.component.html" region="toggle-animation">
</code-pane> </code-pane>
<code-pane path="animations/src/app/open-close.component.4.ts" title="src/app/open-close.component.ts" region="toggle-animation" language="typescript"> <code-pane path="animations/src/app/open-close.component.4.ts" header="src/app/open-close.component.ts" region="toggle-animation" language="typescript">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -188,7 +188,7 @@ However, selective child animations can still be run on a disabled parent in one
To disable all animations for an Angular app, place the `@.disabled` host binding on the topmost Angular component. To disable all animations for an Angular app, place the `@.disabled` host binding on the topmost Angular component.
<code-example path="animations/src/app/app.component.ts" title="src/app/app.component.ts" region="toggle-app-animations" language="typescript" linenums="false"> <code-example path="animations/src/app/app.component.ts" header="src/app/app.component.ts" region="toggle-app-animations" language="typescript" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -200,12 +200,12 @@ To disable all animations for an Angular app, place the `@.disabled` host bindin
The animation `trigger()` function emits *callbacks* when it starts and when it finishes. In the example below we have a component that contains an `openClose` trigger. The animation `trigger()` function emits *callbacks* when it starts and when it finishes. In the example below we have a component that contains an `openClose` trigger.
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" region="events1" language="typescript" linenums="false"> <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" region="events1" language="typescript" linenums="false">
</code-example> </code-example>
In the HTML template, the animation event is passed back via `$event`, as `@trigger.start` and `@trigger.done`, where `trigger` is the name of the trigger being used. In our example, the trigger `openClose` appears as follows. In the HTML template, the animation event is passed back via `$event`, as `@trigger.start` and `@trigger.done`, where `trigger` is the name of the trigger being used. In our example, the trigger `openClose` appears as follows.
<code-example path="animations/src/app/open-close.component.3.html" title="src/app/open-close.component.html" region="callbacks"> <code-example path="animations/src/app/open-close.component.3.html" header="src/app/open-close.component.html" region="callbacks">
</code-example> </code-example>
A potential use for animation callbacks could be to cover for a slow API call, such as a database lookup. For example, you could set up the **InProgress** button to have its own looping animation where it pulsates or does some other visual motion while the backend system operation finishes. A potential use for animation callbacks could be to cover for a slow API call, such as a database lookup. For example, you could set up the **InProgress** button to have its own looping animation where it pulsates or does some other visual motion while the backend system operation finishes.
@ -216,7 +216,7 @@ An animation can influence an end user to *perceive* the operation as faster, ev
Callbacks can serve as a debugging tool, for example in conjunction with `console.warn()` to view the application's progress in a browser's Developer JavaScript Console. The following code snippet creates console log output for our original example, a button with the two states of `open` and `closed`. Callbacks can serve as a debugging tool, for example in conjunction with `console.warn()` to view the application's progress in a browser's Developer JavaScript Console. The following code snippet creates console log output for our original example, a button with the two states of `open` and `closed`.
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" region="events" language="typescript" linenums="false"> <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" region="events" language="typescript" linenums="false">
</code-example> </code-example>
{@a keyframes} {@a keyframes}
@ -233,7 +233,7 @@ Angular's `keyframe()` function is similar to keyframes in CSS. Keyframes allow
The code for this color change might look like this. The code for this color change might look like this.
<code-example path="animations/src/app/status-slider.component.ts" title="src/app/status-slider.component.ts" region="keyframes" language="typescript" linenums="false"> <code-example path="animations/src/app/status-slider.component.ts" header="src/app/status-slider.component.ts" region="keyframes" language="typescript" linenums="false">
</code-example> </code-example>
### Offset ### Offset
@ -248,7 +248,7 @@ Defining offsets for keyframes is optional. If you omit them, evenly spaced offs
The code with offsets specified would be as follows. The code with offsets specified would be as follows.
<code-example path="animations/src/app/status-slider.component.ts" title="src/app/status-slider.component.ts" region="keyframesWithOffsets" language="typescript"> <code-example path="animations/src/app/status-slider.component.ts" header="src/app/status-slider.component.ts" region="keyframesWithOffsets" language="typescript">
</code-example> </code-example>
You can combine keyframes with `duration`, `delay`, and `easing` within a single animation. You can combine keyframes with `duration`, `delay`, and `easing` within a single animation.
@ -269,7 +269,7 @@ Here's an example of using keyframes to create a pulse effect:
The code snippet for this animation might look like this. The code snippet for this animation might look like this.
<code-example path="animations/src/app/open-close.component.1.ts" title="src/app/open-close.component.ts" region="trigger" language="typescript" linenums="false"> <code-example path="animations/src/app/open-close.component.1.ts" header="src/app/open-close.component.ts" region="trigger" language="typescript" linenums="false">
</code-example> </code-example>
### Animatable properties and units ### Animatable properties and units
@ -292,7 +292,7 @@ In these cases, you can use a special wildcard `*` property value under `style()
In this example, we have a trigger called `shrinkOut`, used when an HTML element leaves the page. The animation takes whatever height the element has before it leaves, and animates from that height to zero. In this example, we have a trigger called `shrinkOut`, used when an HTML element leaves the page. The animation takes whatever height the element has before it leaves, and animates from that height to zero.
<code-example path="animations/src/app/hero-list-auto.component.ts" title="src/app/hero-list-auto.component.ts" region="auto-calc" language="typescript" linenums="false"></code-example> <code-example path="animations/src/app/hero-list-auto.component.ts" header="src/app/hero-list-auto.component.ts" region="auto-calc" language="typescript" linenums="false"></code-example>
### Keyframes summary ### Keyframes summary

View File

@ -34,7 +34,7 @@ For details about `tsconfig.json`, see the official
The [Setup](guide/setup) guide uses the following `tsconfig.json`: The [Setup](guide/setup) guide uses the following `tsconfig.json`:
<code-example path="quickstart/src/tsconfig.1.json" title="tsconfig.json" linenums="false"></code-example> <code-example path="quickstart/src/tsconfig.1.json" header="tsconfig.json" linenums="false"></code-example>
This file contains options and flags that are essential for Angular applications. This file contains options and flags that are essential for Angular applications.

View File

@ -538,7 +538,7 @@ inject it into the service, and prepend the origin to the request URL.
Start by changing the `HeroService` constructor to take a second `origin` parameter that is optionally injected via the `APP_BASE_HREF` token. Start by changing the `HeroService` constructor to take a second `origin` parameter that is optionally injected via the `APP_BASE_HREF` token.
<code-example path="universal/src/app/hero.service.ts" region="ctor" title="src/app/hero.service.ts (constructor with optional origin)"> <code-example path="universal/src/app/hero.service.ts" region="ctor" header="src/app/hero.service.ts (constructor with optional origin)">
</code-example> </code-example>
The constructor uses the `@Optional()` directive to prepend the origin to `heroesUrl` _if it exists_. The constructor uses the `@Optional()` directive to prepend the origin to `heroesUrl` _if it exists_.
@ -555,7 +555,7 @@ You don't provide `APP_BASE_HREF` in the browser version, so `heroesUrl` remains
The important bit in the `server.ts` file is the `ngExpressEngine()` function. The important bit in the `server.ts` file is the `ngExpressEngine()` function.
<code-example path="universal/server.ts" title="server.ts" region="ngExpressEngine"> <code-example path="universal/server.ts" header="server.ts" region="ngExpressEngine">
</code-example> </code-example>
The `ngExpressEngine()` function is a wrapper around Universal's `renderModuleFactory()` function which turns a client's requests into server-rendered HTML pages. The `ngExpressEngine()` function is a wrapper around Universal's `renderModuleFactory()` function which turns a client's requests into server-rendered HTML pages.
@ -602,7 +602,7 @@ Because we use routing, we can easily recognize the three types of requests and
A Node Express server is a pipeline of middleware that filters and processes URL requests one after the other. A Node Express server is a pipeline of middleware that filters and processes URL requests one after the other.
You configure the Node Express server pipeline with calls to `app.get()` like this one for data requests. You configure the Node Express server pipeline with calls to `app.get()` like this one for data requests.
<code-example path="universal/server.ts" title="server.ts (data URL)" region="data-request" linenums="false"> <code-example path="universal/server.ts" header="server.ts (data URL)" region="data-request" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -617,7 +617,7 @@ You configure the Node Express server pipeline with calls to `app.get()` like th
The following code filters for request URLs with no extensions and treats them as navigation requests. The following code filters for request URLs with no extensions and treats them as navigation requests.
<code-example path="universal/server.ts" title="server.ts (navigation)" region="navigation-request" linenums="false"> <code-example path="universal/server.ts" header="server.ts (navigation)" region="navigation-request" linenums="false">
</code-example> </code-example>
### Serving static files safely ### Serving static files safely
@ -629,7 +629,7 @@ To ensure that clients can only download the files that they are permitted to se
The following Node Express code routes all remaining requests to `/dist`, and returns a `404 - NOT FOUND` error if the file isn't found. The following Node Express code routes all remaining requests to `/dist`, and returns a `404 - NOT FOUND` error if the file isn't found.
<code-example path="universal/server.ts" title="server.ts (static files)" region="static" linenums="false"> <code-example path="universal/server.ts" header="server.ts (static files)" region="static" linenums="false">
</code-example> </code-example>

View File

@ -222,13 +222,13 @@ instructions in the [Setup](guide/setup) guide, selectively copying code from th
You also need to install the `@angular/upgrade` package via `npm install @angular/upgrade --save` You 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 title="system.config.js"> <code-example header="system.config.js">
'@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js',
</code-example> </code-example>
Next, create an `app.module.ts` file and add the following `NgModule` class: Next, create an `app.module.ts` file and add the following `NgModule` class:
<code-example title="app.module.ts"> <code-example header="app.module.ts">
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
@ -257,7 +257,7 @@ declaration on its `NgModule` decorator.
You can now link the AngularJS and Angular modules together using `downgradeModule()`. You can now link the AngularJS and Angular modules together using `downgradeModule()`.
<code-example title="app.module.ts"> <code-example header="app.module.ts">
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { downgradeModule } from '@angular/upgrade/static'; import { downgradeModule } from '@angular/upgrade/static';
@ -314,7 +314,7 @@ An easy way to copy them is to add each to the `copy-dist-files.js`file.
You also need to pass the generated `MainAngularModuleFactory` to `downgradeModule()` instead of the You also need to pass the generated `MainAngularModuleFactory` to `downgradeModule()` instead of the
custom bootstrap function: custom bootstrap function:
<code-example title="app/main-aot.ts"> <code-example header="app/main-aot.ts">
import { downgradeModule } from '@angular/upgrade/static'; import { downgradeModule } from '@angular/upgrade/static';
import { MainAngularModuleNgFactory } from '../aot/app/app.module.ngfactory'; import { MainAngularModuleNgFactory } from '../aot/app/app.module.ngfactory';

View File

@ -162,7 +162,7 @@ Component directives **should not** use the following attributes:
An AngularJS component directive that is fully aligned with the Angular An AngularJS component directive that is fully aligned with the Angular
architecture may look something like this: architecture may look something like this:
<code-example path="upgrade-module/src/app/hero-detail.directive.ts" title="hero-detail.directive.ts"> <code-example path="upgrade-module/src/app/hero-detail.directive.ts" header="hero-detail.directive.ts">
</code-example> </code-example>
AngularJS 1.5 introduces the [component API](https://docs.angularjs.org/api/ng/type/angular.Module#component) AngularJS 1.5 introduces the [component API](https://docs.angularjs.org/api/ng/type/angular.Module#component)
@ -176,7 +176,7 @@ this API for component directives for several reasons:
The component directive example from above looks like this when expressed The component directive example from above looks like this when expressed
using the component API: using the component API:
<code-example path="upgrade-module/src/app/upgrade-io/hero-detail.component.ts" region="hero-detail-io" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/upgrade-io/hero-detail.component.ts" region="hero-detail-io" header="hero-detail.component.ts">
</code-example> </code-example>
Controller lifecycle hook methods `$onInit()`, `$onDestroy()`, and `$onChanges()` Controller lifecycle hook methods `$onInit()`, `$onDestroy()`, and `$onChanges()`
@ -400,7 +400,7 @@ then ask the `UpgradeModule` to bootstrap the AngularJS bits next.
In an AngularJS application you have a root AngularJS module, which will also In an AngularJS application you have a root AngularJS module, which will also
be used to bootstrap the AngularJS application. be used to bootstrap the AngularJS application.
<code-example path="upgrade-module/src/app/ajs-bootstrap/app.module.ts" region="ng1module" title="app.module.ts"> <code-example path="upgrade-module/src/app/ajs-bootstrap/app.module.ts" region="ng1module" header="app.module.ts">
</code-example> </code-example>
Pure AngularJS applications can be automatically bootstrapped by using an `ng-app` Pure AngularJS applications can be automatically bootstrapped by using an `ng-app`
@ -418,7 +418,7 @@ You can remove the `ng-app` and `ng-strict-di` directives from the HTML
and instead switch to calling `angular.bootstrap` from JavaScript, which and instead switch to calling `angular.bootstrap` from JavaScript, which
will result in the same thing: will result in the same thing:
<code-example path="upgrade-module/src/app/ajs-bootstrap/app.module.ts" region="bootstrap" title="app.module.ts"> <code-example path="upgrade-module/src/app/ajs-bootstrap/app.module.ts" region="bootstrap" header="app.module.ts">
</code-example> </code-example>
To begin converting your AngularJS application to a hybrid, you need to load the Angular framework. To begin converting your AngularJS application to a hybrid, you need to load the Angular framework.
@ -428,12 +428,12 @@ selectively copying code from the [QuickStart github repository](https://github.
You also need to install the `@angular/upgrade` package via `npm install @angular/upgrade --save` You 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" header="systemjs.config.js (map)">
</code-example> </code-example>
Next, create an `app.module.ts` file and add the following `NgModule` class: Next, create an `app.module.ts` file and add the following `NgModule` class:
<code-example path="upgrade-module/src/app/ajs-a-hybrid-bootstrap/app.module.ts" region="ngmodule" title="app.module.ts"> <code-example path="upgrade-module/src/app/ajs-a-hybrid-bootstrap/app.module.ts" region="ngmodule" header="app.module.ts">
</code-example> </code-example>
This bare minimum `NgModule` imports `BrowserModule`, the module every Angular browser-based app must have. This bare minimum `NgModule` imports `BrowserModule`, the module every Angular browser-based app must have.
@ -453,7 +453,7 @@ AngularJS will own the root template of the application.
Now you can bootstrap `AppModule` using the `platformBrowserDynamic.bootstrapModule` method. Now you can bootstrap `AppModule` using the `platformBrowserDynamic.bootstrapModule` method.
<code-example path="upgrade-module/src/app/ajs-a-hybrid-bootstrap/app.module.ts" region="bootstrap" title="app.module.ts'"> <code-example path="upgrade-module/src/app/ajs-a-hybrid-bootstrap/app.module.ts" region="bootstrap" header="app.module.ts'">
</code-example> </code-example>
Congratulations! You're running a hybrid application! The Congratulations! You're running a hybrid application! The
@ -470,14 +470,14 @@ previously AngularJS but has been rewritten for Angular.
Say you have a simple Angular component that shows information about a hero: Say you have a simple Angular component that shows information about a hero:
<code-example path="upgrade-module/src/app/downgrade-static/hero-detail.component.ts" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/downgrade-static/hero-detail.component.ts" header="hero-detail.component.ts">
</code-example> </code-example>
If you want to use this component from AngularJS, you need to *downgrade* it If you want to use this component from AngularJS, you need to *downgrade* it
using the `downgradeComponent()` method. The result is an AngularJS using the `downgradeComponent()` method. The result is an AngularJS
*directive*, which you can then register in the AngularJS module: *directive*, which you can then register in the AngularJS module:
<code-example path="upgrade-module/src/app/downgrade-static/app.module.ts" region="downgradecomponent" title="app.module.ts"> <code-example path="upgrade-module/src/app/downgrade-static/app.module.ts" region="downgradecomponent" header="app.module.ts">
</code-example> </code-example>
Because `HeroDetailComponent` is an Angular component, you must also add it to the Because `HeroDetailComponent` is an Angular component, you must also add it to the
@ -487,7 +487,7 @@ And because this component is being used from the AngularJS module, and is an en
the Angular application, you must add it to the `entryComponents` for the the Angular application, you must add it to the `entryComponents` for the
NgModule. NgModule.
<code-example path="upgrade-module/src/app/downgrade-static/app.module.ts" region="ngmodule" title="app.module.ts"> <code-example path="upgrade-module/src/app/downgrade-static/app.module.ts" region="ngmodule" header="app.module.ts">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -515,7 +515,7 @@ have *inputs and outputs* that connect them to the outside world. An
Angular hero detail component with inputs and outputs might look Angular hero detail component with inputs and outputs might look
like this: like this:
<code-example path="upgrade-module/src/app/downgrade-io/hero-detail.component.ts" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/downgrade-io/hero-detail.component.ts" header="hero-detail.component.ts">
</code-example> </code-example>
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
@ -583,7 +583,7 @@ introduced in AngularJS 1.5.
A simple example of an upgradable component is one that just has a template A simple example of an upgradable component is one that just has a template
and a controller: and a controller:
<code-example path="upgrade-module/src/app/upgrade-static/hero-detail.component.ts" region="hero-detail" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/upgrade-static/hero-detail.component.ts" region="hero-detail" header="hero-detail.component.ts">
</code-example> </code-example>
You can *upgrade* this component to Angular using the `UpgradeComponent` class. You can *upgrade* this component to Angular using the `UpgradeComponent` class.
@ -591,10 +591,10 @@ By creating a new Angular **directive** that extends `UpgradeComponent` and doin
inside its constructor, you have a fully upgraded AngularJS component to be used inside Angular. inside its constructor, you have a fully upgraded 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.
<code-example path="upgrade-module/src/app/upgrade-static/hero-detail.component.ts" region="hero-detail-upgrade" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/upgrade-static/hero-detail.component.ts" region="hero-detail-upgrade" header="hero-detail.component.ts">
</code-example> </code-example>
<code-example path="upgrade-module/src/app/upgrade-static/app.module.ts" region="hero-detail-upgrade" title="app.module.ts"> <code-example path="upgrade-module/src/app/upgrade-static/app.module.ts" region="hero-detail-upgrade" header="app.module.ts">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -691,16 +691,16 @@ observing the following rules:
For example, imagine a hero detail AngularJS component directive For example, imagine a hero detail AngularJS component directive
with one input and one output: with one input and one output:
<code-example path="upgrade-module/src/app/upgrade-io/hero-detail.component.ts" region="hero-detail-io" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/upgrade-io/hero-detail.component.ts" region="hero-detail-io" header="hero-detail.component.ts">
</code-example> </code-example>
You can upgrade this component to Angular, annotate inputs and outputs in the upgrade directive, You 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:
<code-example path="upgrade-module/src/app/upgrade-io/hero-detail.component.ts" region="hero-detail-io-upgrade" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/upgrade-io/hero-detail.component.ts" region="hero-detail-io-upgrade" header="hero-detail.component.ts">
</code-example> </code-example>
<code-example path="upgrade-module/src/app/upgrade-io/container.component.ts" title="container.component.ts"> <code-example path="upgrade-module/src/app/upgrade-io/container.component.ts" header="container.component.ts">
</code-example> </code-example>
### Projecting AngularJS Content into Angular Components ### Projecting AngularJS Content into Angular Components
@ -716,7 +716,7 @@ is able to make these two features interoperate.
Angular components that support content projection make use of an `<ng-content>` Angular components that support content projection make use of an `<ng-content>`
tag within them. Here's an example of such a component: tag within them. Here's an example of such a component:
<code-example path="upgrade-module/src/app/ajs-to-a-projection/hero-detail.component.ts" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/ajs-to-a-projection/hero-detail.component.ts" header="hero-detail.component.ts">
</code-example> </code-example>
When using the component from AngularJS, you can supply contents for it. Just When using the component from AngularJS, you can supply contents for it. Just
@ -745,13 +745,13 @@ When an AngularJS component directive supports transclusion, it may use
the `ng-transclude` directive in its template to mark the transclusion the `ng-transclude` directive in its template to mark the transclusion
point: point:
<code-example path="upgrade-module/src/app/a-to-ajs-transclusion/hero-detail.component.ts" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/a-to-ajs-transclusion/hero-detail.component.ts" header="hero-detail.component.ts">
</code-example> </code-example>
If you upgrade this component and use it from Angular, you can populate If you upgrade this component and use it from Angular, you can populate
the component tag with contents that will then get transcluded: the component tag with contents that will then get transcluded:
<code-example path="upgrade-module/src/app/a-to-ajs-transclusion/container.component.ts" title="container.component.ts"> <code-example path="upgrade-module/src/app/a-to-ajs-transclusion/container.component.ts" header="container.component.ts">
</code-example> </code-example>
### Making AngularJS Dependencies Injectable to Angular ### Making AngularJS Dependencies Injectable to Angular
@ -765,7 +765,7 @@ In these situations, it is possible to *upgrade* an AngularJS provider to
Angular. This makes it possible to then inject it somewhere in Angular Angular. This makes it possible to then inject it somewhere in Angular
code. For example, you might have a service called `HeroesService` in AngularJS: code. For example, you might have a service called `HeroesService` in AngularJS:
<code-example path="upgrade-module/src/app/ajs-to-a-providers/heroes.service.ts" title="heroes.service.ts"> <code-example path="upgrade-module/src/app/ajs-to-a-providers/heroes.service.ts" header="heroes.service.ts">
</code-example> </code-example>
You can upgrade the service using a Angular [factory provider](guide/dependency-injection-providers#factory-providers) You can upgrade the service using a Angular [factory provider](guide/dependency-injection-providers#factory-providers)
@ -786,17 +786,17 @@ and append the "Service" suffix to create the class name.
</div> </div>
<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" header="ajs-upgraded-providers.ts">
</code-example> </code-example>
You can then provide the service to Angular by adding it to the `@NgModule`: You can then provide the service to Angular by adding it to the `@NgModule`:
<code-example path="upgrade-module/src/app/ajs-to-a-providers/app.module.ts" region="register" title="app.module.ts"> <code-example path="upgrade-module/src/app/ajs-to-a-providers/app.module.ts" region="register" header="app.module.ts">
</code-example> </code-example>
Then use the service inside your component by injecting it in the component constructor using its class as a type annotation: Then use the service inside your component by injecting it in the component constructor using its class as a type annotation:
<code-example path="upgrade-module/src/app/ajs-to-a-providers/hero-detail.component.ts" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/ajs-to-a-providers/hero-detail.component.ts" header="hero-detail.component.ts">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -818,24 +818,24 @@ in Angular while retaining components written in AngularJS.
For example, you might have an Angular service called `Heroes`: For example, you might have an Angular service called `Heroes`:
<code-example path="upgrade-module/src/app/a-to-ajs-providers/heroes.ts" title="heroes.ts"> <code-example path="upgrade-module/src/app/a-to-ajs-providers/heroes.ts" header="heroes.ts">
</code-example> </code-example>
Again, as with Angular components, register the provider with the `NgModule` by adding it to the module's `providers` list. Again, as with Angular components, register the provider with the `NgModule` by adding it to the module's `providers` list.
<code-example path="upgrade-module/src/app/a-to-ajs-providers/app.module.ts" region="ngmodule" title="app.module.ts"> <code-example path="upgrade-module/src/app/a-to-ajs-providers/app.module.ts" region="ngmodule" header="app.module.ts">
</code-example> </code-example>
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:
<code-example path="upgrade-module/src/app/a-to-ajs-providers/app.module.ts" region="register" title="app.module.ts"> <code-example path="upgrade-module/src/app/a-to-ajs-providers/app.module.ts" region="register" header="app.module.ts">
</code-example> </code-example>
After this, the service is injectable anywhere in AngularJS code: After this, the service is injectable anywhere in AngularJS code:
<code-example path="upgrade-module/src/app/a-to-ajs-providers/hero-detail.component.ts" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/a-to-ajs-providers/hero-detail.component.ts" header="hero-detail.component.ts">
</code-example> </code-example>
## Using Ahead-of-time compilation with hybrid apps ## Using Ahead-of-time compilation with hybrid apps
@ -853,7 +853,7 @@ An easy way to copy them is by adding each to the `copy-dist-files.js` file.
You'll need to use the generated `AppModuleFactory`, instead of the original `AppModule` to You'll need to use the generated `AppModuleFactory`, instead of the original `AppModule` to
bootstrap the hybrid app: bootstrap the hybrid app:
<code-example path="upgrade-phonecat-2-hybrid/app/main-aot.ts" title="app/main-aot.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/main-aot.ts" header="app/main-aot.ts">
</code-example> </code-example>
And that's all you need do to get the full benefit of AOT for Angular apps! And that's all you need do to get the full benefit of AOT for Angular apps!
@ -1100,20 +1100,20 @@ out of TypeScript's type system. For instance, you can annotate the checkmark
filter so that it explicitly expects booleans as arguments. This makes it clearer filter so that it explicitly expects booleans as arguments. This makes it clearer
what the filter is supposed to do. what the filter is supposed to do.
<code-example path="upgrade-phonecat-1-typescript/app/core/checkmark/checkmark.filter.ts" title="app/core/checkmark/checkmark.filter.ts"> <code-example path="upgrade-phonecat-1-typescript/app/core/checkmark/checkmark.filter.ts" header="app/core/checkmark/checkmark.filter.ts">
</code-example> </code-example>
In the `Phone` service, you can explicitly annotate the `$resource` service dependency In the `Phone` service, you can explicitly annotate the `$resource` service dependency
as an `angular.resource.IResourceService` - a type defined by the AngularJS typings. as an `angular.resource.IResourceService` - a type defined by the AngularJS typings.
<code-example path="upgrade-phonecat-1-typescript/app/core/phone/phone.service.ts" title="app/core/phone/phone.service.ts"> <code-example path="upgrade-phonecat-1-typescript/app/core/phone/phone.service.ts" header="app/core/phone/phone.service.ts">
</code-example> </code-example>
You can apply the same trick to the application's route configuration file in `app.config.ts`, You can apply the same trick to the application's route configuration file in `app.config.ts`,
where you are using the location and route services. By annotating them accordingly TypeScript where you are using the location and route services. By annotating them accordingly TypeScript
can verify you're calling their APIs with the correct kinds of arguments. can verify you're calling their APIs with the correct kinds of arguments.
<code-example path="upgrade-phonecat-1-typescript/app/app.config.ts" title="app/app.config.ts"> <code-example path="upgrade-phonecat-1-typescript/app/app.config.ts" header="app/app.config.ts">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -1142,7 +1142,7 @@ class as a component controller and AngularJS will happily use it.
Here's what the new class for the phone list component controller looks like: Here's what the new class for the phone list component controller looks like:
<code-example path="upgrade-phonecat-1-typescript/app/phone-list/phone-list.component.ts" title="app/phone-list/phone-list.component.ts"> <code-example path="upgrade-phonecat-1-typescript/app/phone-list/phone-list.component.ts" header="app/phone-list/phone-list.component.ts">
</code-example> </code-example>
What was previously done in the controller function is now done in the class What was previously done in the controller function is now done in the class
@ -1160,7 +1160,7 @@ controller members.
In the Phone detail controller, you'll have two members: One for the phone In the Phone detail controller, you'll have two members: One for the phone
that the user is looking at and another for the URL of the currently displayed image: that the user is looking at and another for the URL of the currently displayed image:
<code-example path="upgrade-phonecat-1-typescript/app/phone-detail/phone-detail.component.ts" title="app/phone-detail/phone-detail.component.ts"> <code-example path="upgrade-phonecat-1-typescript/app/phone-detail/phone-detail.component.ts" header="app/phone-detail/phone-detail.component.ts">
</code-example> </code-example>
This makes the controller code look a lot more like Angular already. You're This makes the controller code look a lot more like Angular already. You're
@ -1220,14 +1220,14 @@ want to have to change all the image and data paths used in the application code
the development setup. For that reason, you'll add a `<base>` tag to `index.html`, which will the development setup. For that reason, you'll add a `<base>` tag to `index.html`, which will
cause relative URLs to be resolved back to the `/app` directory: cause relative URLs to be resolved back to the `/app` directory:
<code-example path="upgrade-phonecat-2-hybrid/index.html" region="base" title="index.html"> <code-example path="upgrade-phonecat-2-hybrid/index.html" region="base" header="index.html">
</code-example> </code-example>
Now you can load Angular via SystemJS. You'll add the Angular polyfills and the Now you can load Angular via SystemJS. You'll add the Angular polyfills and the
SystemJS config to the end of the `<head>` section, and then you'll use `System.import` SystemJS config to the end of the `<head>` section, and then you'll use `System.import`
to load the actual application: to load the actual application:
<code-example path="upgrade-phonecat-2-hybrid/index.html" region="angular" title="index.html"> <code-example path="upgrade-phonecat-2-hybrid/index.html" region="angular" header="index.html">
</code-example> </code-example>
You also need to make a couple of adjustments You also need to make a couple of adjustments
@ -1239,7 +1239,7 @@ instead of using the `<base>` URL.
Install the `upgrade` package via `npm install @angular/upgrade --save` 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" header="systemjs.config.js">
</code-example> </code-example>
### Creating the _AppModule_ ### Creating the _AppModule_
@ -1249,12 +1249,12 @@ 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:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ajs.ts" title="app.module.ajs.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ajs.ts" header="app.module.ajs.ts">
</code-example> </code-example>
Now create a new `app.module.ts` with the minimum `NgModule` class: Now create a new `app.module.ts` with the minimum `NgModule` class:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="bare" title="app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="bare" header="app.module.ts">
</code-example> </code-example>
### Bootstrapping a hybrid PhoneCat ### Bootstrapping a hybrid PhoneCat
@ -1271,7 +1271,7 @@ instead.
First, remove the `ng-app` attribute from `index.html`. First, remove the `ng-app` attribute from `index.html`.
Then import `UpgradeModule` in the `AppModule`, and override its `ngDoBootstrap` method: Then import `UpgradeModule` in the `AppModule`, and override its `ngDoBootstrap` method:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="upgrademodule" title="app/app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="upgrademodule" header="app/app.module.ts">
</code-example> </code-example>
Note that you are bootstrapping the AngularJS module from inside `ngDoBootstrap`. Note that you are bootstrapping the AngularJS module from inside `ngDoBootstrap`.
@ -1283,7 +1283,7 @@ Finally, bootstrap the `AppModule` in `app/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.
<code-example path="upgrade-phonecat-2-hybrid/app/main.ts" region="bootstrap" title="app/main.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/main.ts" region="bootstrap" header="app/main.ts">
</code-example> </code-example>
Now you're running both AngularJS and Angular at the same time. That's pretty Now you're running both AngularJS and Angular at the same time. That's pretty
@ -1328,13 +1328,13 @@ In the new version, you import the Angular HTTP module and call its `Http` servi
Re-open the `app.module.ts` file, import and add `HttpModule` to the `imports` array of the `AppModule`: Re-open the `app.module.ts` file, import and add `HttpModule` to the `imports` array of the `AppModule`:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="httpmodule" title="app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="httpmodule" header="app.module.ts">
</code-example> </code-example>
Now you're ready to upgrade the Phone service itself. Replace the ngResource-based Now you're ready to upgrade the Phone service itself. Replace the ngResource-based
service in `phone.service.ts` with a TypeScript class decorated as `@Injectable`: service in `phone.service.ts` with a TypeScript class decorated as `@Injectable`:
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="classdef" title="app/core/phone/phone.service.ts (skeleton)" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="classdef" header="app/core/phone/phone.service.ts (skeleton)" linenums="false">
</code-example> </code-example>
The `@Injectable` decorator will attach some dependency injection metadata The `@Injectable` decorator will attach some dependency injection metadata
@ -1348,24 +1348,24 @@ be injected to it and it is stored as a private field. The service is then
used in the two instance methods, one of which loads the list of all phones, used in the two instance methods, one of which loads the list of all phones,
and the other loads the details of a specified phone: and the other loads the details of a specified phone:
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="fullclass" title="app/core/phone/phone.service.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="fullclass" header="app/core/phone/phone.service.ts">
</code-example> </code-example>
The methods now return observables of type `PhoneData` and `PhoneData[]`. This is The methods now return observables of type `PhoneData` and `PhoneData[]`. This is
a type you don't have yet. Add a simple interface for it: a type you don't have yet. Add a simple interface for it:
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="phonedata-interface" title="app/core/phone/phone.service.ts (interface)" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="phonedata-interface" header="app/core/phone/phone.service.ts (interface)" linenums="false">
</code-example> </code-example>
`@angular/upgrade/static` has a `downgradeInjectable` method for the purpose of making `@angular/upgrade/static` has a `downgradeInjectable` method for the purpose of making
Angular services available to AngularJS code. Use it to plug in the `Phone` service: Angular services available to AngularJS code. Use it to plug in the `Phone` service:
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="downgrade-injectable" title="app/core/phone/phone.service.ts (downgrade)" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="downgrade-injectable" header="app/core/phone/phone.service.ts (downgrade)" linenums="false">
</code-example> </code-example>
Here's the full, final code for the service: Here's the full, final code for the service:
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" title="app/core/phone/phone.service.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" header="app/core/phone/phone.service.ts">
</code-example> </code-example>
Notice that you're importing the `map` operator of the RxJS `Observable` separately. Notice that you're importing the `map` operator of the RxJS `Observable` separately.
@ -1374,7 +1374,7 @@ Do this for every RxJS operator.
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, you register it with the `NgModule` providers: Because it's an Angular service, you register it with the `NgModule` providers:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="phone" title="app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="phone" header="app.module.ts">
</code-example> </code-example>
Now that you are loading `phone.service.ts` through an import that is resolved Now that you are loading `phone.service.ts` through an import that is resolved
@ -1386,10 +1386,10 @@ At this point, you can switch the two components to use the new service
instead of the old one. While you `$inject` it as the downgraded `phone` factory, instead of the old one. While you `$inject` it as the downgraded `phone` factory,
it's really an instance of the `Phone` class and you annotate its type accordingly: it's really an instance of the `Phone` class and you annotate its type accordingly:
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ajs.ts" title="app/phone-list/phone-list.component.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ajs.ts" header="app/phone-list/phone-list.component.ts">
</code-example> </code-example>
<code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.component.ajs.ts" title="app/phone-detail/phone-detail.component.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.component.ajs.ts" header="app/phone-detail/phone-detail.component.ts">
</code-example> </code-example>
Now there are two AngularJS components using an Angular service! Now there are two AngularJS components using an Angular service!
@ -1418,7 +1418,7 @@ an Angular component by just renaming the controller class and turning the
AngularJS component definition object into an Angular `@Component` decorator. AngularJS component definition object into an Angular `@Component` decorator.
You can then also remove the static `$inject` property from the class: You can then also remove the static `$inject` property from the class:
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ts" region="initialclass" title="app/phone-list/phone-list.component.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ts" region="initialclass" header="app/phone-list/phone-list.component.ts">
</code-example> </code-example>
The `selector` attribute is a CSS selector that defines where on the page the component The `selector` attribute is a CSS selector that defines where on the page the component
@ -1430,14 +1430,14 @@ Now convert the template of this component into Angular syntax.
The search controls replace the AngularJS `$ctrl` expressions The search controls replace the AngularJS `$ctrl` expressions
with Angular's two-way `[(ngModel)]` binding syntax: with Angular's two-way `[(ngModel)]` binding syntax:
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.template.html" region="controls" title="app/phone-list/phone-list.template.html (search controls)" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.template.html" region="controls" header="app/phone-list/phone-list.template.html (search controls)" linenums="false">
</code-example> </code-example>
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.
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.template.html" region="list" title="app/phone-list/phone-list.template.html (phones)" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.template.html" region="list" header="app/phone-list/phone-list.template.html (phones)" linenums="false">
</code-example> </code-example>
#### No Angular _filter_ or _orderBy_ filters #### No Angular _filter_ or _orderBy_ filters
@ -1448,7 +1448,7 @@ so you need to do the filtering and sorting yourself.
You replaced the `filter` and `orderBy` filters with bindings to the `getPhones()` controller method, You 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" header="app/phone-list/phone-list.component.ts">
</code-example> </code-example>
Now you need to downgrade the Angular component so you can use it in AngularJS. Now you need to downgrade the Angular component so you can use it in AngularJS.
@ -1458,21 +1458,21 @@ 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
that the return value of the `downgradeComponent` method is a directive factory. that the return value of the `downgradeComponent` method is a directive factory.
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ts" region="downgrade-component" title="app/phone-list/phone-list.component.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ts" region="downgrade-component" header="app/phone-list/phone-list.component.ts">
</code-example> </code-example>
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 you downgraded it: finally add it to `entryComponents` since you downgraded it:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="phonelist" title="app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="phonelist" header="app.module.ts">
</code-example> </code-example>
Remove the &lt;script&gt; tag for the phone list component from `index.html`. Remove the &lt;script&gt; tag for the phone list component from `index.html`.
Now set the remaining `phone-detail.component.ts` as follows: Now set the remaining `phone-detail.component.ts` as follows:
<code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.component.ts" title="app/phone-detail/phone-detail.component.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.component.ts" header="app/phone-detail/phone-detail.component.ts">
</code-example> </code-example>
This is similar to the phone list component. This is similar to the phone list component.
@ -1487,15 +1487,15 @@ You must upgrade this service via a [factory provider](guide/upgrade#making-angu
to make `$routeParams` an Angular injectable. to make `$routeParams` an Angular injectable.
Do that in a new file called `ajs-upgraded-providers.ts` and import it in `app.module.ts`: Do that in a new file called `ajs-upgraded-providers.ts` and import it in `app.module.ts`:
<code-example path="upgrade-phonecat-2-hybrid/app/ajs-upgraded-providers.ts" title="app/ajs-upgraded-providers.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/ajs-upgraded-providers.ts" header="app/ajs-upgraded-providers.ts">
</code-example> </code-example>
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="routeparams" title="app/app.module.ts ($routeParams)" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="routeparams" header="app/app.module.ts ($routeParams)" linenums="false">
</code-example> </code-example>
Convert the phone detail component template into Angular syntax as follows: Convert the phone detail component template into Angular syntax as follows:
<code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.template.html" title="app/phone-detail/phone-detail.template.html"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.template.html" header="app/phone-detail/phone-detail.template.html">
</code-example> </code-example>
There are several notable changes here: There are several notable changes here:
@ -1524,7 +1524,7 @@ There are several notable changes here:
Add `PhoneDetailComponent` component to the `NgModule` _declarations_ and _entryComponents_: Add `PhoneDetailComponent` component to the `NgModule` _declarations_ and _entryComponents_:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="phonedetail" title="app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="phonedetail" header="app.module.ts">
</code-example> </code-example>
You should now also remove the phone detail component &lt;script&gt; tag from `index.html`. You should now also remove the phone detail component &lt;script&gt; tag from `index.html`.
@ -1540,13 +1540,13 @@ 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:
<code-example path="upgrade-phonecat-2-hybrid/app/core/checkmark/checkmark.pipe.ts" title="app/core/checkmark/checkmark.pipe.ts" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/core/checkmark/checkmark.pipe.ts" header="app/core/checkmark/checkmark.pipe.ts" linenums="false">
</code-example> </code-example>
Now import and declare the newly created pipe and Now import and declare the newly created pipe and
remove the filter &lt;script&gt; tag from `index.html`: remove the filter &lt;script&gt; tag from `index.html`:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="checkmarkpipe" title="app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="checkmarkpipe" header="app.module.ts">
</code-example> </code-example>
### AOT compile the hybrid app ### AOT compile the hybrid app
@ -1557,13 +1557,13 @@ as shown in [the Ahead-of-time Compilation chapter](guide/aot-compiler).
Then change `main-aot.ts` to bootstrap the `AppComponentFactory` that was generated Then change `main-aot.ts` to bootstrap the `AppComponentFactory` that was generated
by the AOT compiler: by the AOT compiler:
<code-example path="upgrade-phonecat-2-hybrid/app/main-aot.ts" title="app/main-aot.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/main-aot.ts" header="app/main-aot.ts">
</code-example> </code-example>
You need to load all the AngularJS files you already use in `index.html` in `aot/index.html` You need to load all the AngularJS files you already use in `index.html` in `aot/index.html`
as well: as well:
<code-example path="upgrade-phonecat-2-hybrid/aot/index.html" title="aot/index.html"> <code-example path="upgrade-phonecat-2-hybrid/aot/index.html" header="aot/index.html">
</code-example> </code-example>
These files need to be copied together with the polyfills. The files the application These files need to be copied together with the polyfills. The files the application
@ -1572,7 +1572,7 @@ needs at runtime, like the `.json` phone lists and images, also need to be copie
Install `fs-extra` via `npm install fs-extra --save-dev` for better file copying, and change Install `fs-extra` via `npm install fs-extra --save-dev` for better file copying, and change
`copy-dist-files.js` to the following: `copy-dist-files.js` to the following:
<code-example path="upgrade-phonecat-2-hybrid/copy-dist-files.js" title="copy-dist-files.js"> <code-example path="upgrade-phonecat-2-hybrid/copy-dist-files.js" header="copy-dist-files.js">
</code-example> </code-example>
And that's all you need to use AOT while upgrading your app! And that's all you need to use AOT while upgrading your app!
@ -1593,7 +1593,7 @@ at the top of the applications component tree.
You don't yet have such a root component, because the app is still managed as an AngularJS app. You 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:
<code-example path="upgrade-phonecat-3-final/app/app.component.ts" title="app/app.component.ts"> <code-example path="upgrade-phonecat-3-final/app/app.component.ts" header="app/app.component.ts">
</code-example> </code-example>
It has a simple template that only includes the `<router-outlet>. It has a simple template that only includes the `<router-outlet>.
@ -1605,7 +1605,7 @@ 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`.
It replaces the old AngularJS `ng-view` directive: It replaces the old AngularJS `ng-view` directive:
<code-example path="upgrade-phonecat-3-final/index.html" region="appcomponent" title="index.html (body)" linenums="false"> <code-example path="upgrade-phonecat-3-final/index.html" region="appcomponent" header="index.html (body)" linenums="false">
</code-example> </code-example>
#### Create the _Routing Module_ #### Create the _Routing Module_
@ -1615,7 +1615,7 @@ The details of Angular router configuration are best left to the [Routing docume
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_).
<code-example path="upgrade-phonecat-3-final/app/app-routing.module.ts" title="app/app-routing.module.ts"> <code-example path="upgrade-phonecat-3-final/app/app-routing.module.ts" header="app/app-routing.module.ts">
</code-example> </code-example>
This module defines a `routes` object with two routes to the two phone components This module defines a `routes` object with two routes to the two phone components
@ -1633,7 +1633,7 @@ insert its view into the host web page.
You must also remove the bootstrap of the AngularJS module from `ngDoBootstrap()` in `app.module.ts` You must also remove the bootstrap of the AngularJS module from `ngDoBootstrap()` in `app.module.ts`
and the `UpgradeModule` import. and the `UpgradeModule` import.
<code-example path="upgrade-phonecat-3-final/app/app.module.ts" title="app/app.module.ts"> <code-example path="upgrade-phonecat-3-final/app/app.module.ts" header="app/app.module.ts">
</code-example> </code-example>
And since you are routing to `PhoneListComponent` and `PhoneDetailComponent` directly rather than And since you are routing to `PhoneListComponent` and `PhoneDetailComponent` directly rather than
@ -1646,7 +1646,7 @@ You no longer have to hardcode the links to phone details in the phone list.
You can generate data bindings for each phone's `id` to the `routerLink` directive You 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`:
<code-example path="upgrade-phonecat-3-final/app/phone-list/phone-list.template.html" region="list" title="app/phone-list/phone-list.template.html (list with links)" linenums="false"> <code-example path="upgrade-phonecat-3-final/app/phone-list/phone-list.template.html" region="list" header="app/phone-list/phone-list.template.html (list with links)" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -1661,7 +1661,7 @@ The Angular router passes route parameters differently.
Correct the `PhoneDetail` component constructor to expect an injected `ActivatedRoute` object. Correct the `PhoneDetail` component constructor to expect an injected `ActivatedRoute` object.
Extract the `phoneId` from the `ActivatedRoute.snapshot.params` and fetch the phone data as before: Extract the `phoneId` from the `ActivatedRoute.snapshot.params` and fetch the phone data as before:
<code-example path="upgrade-phonecat-3-final/app/phone-detail/phone-detail.component.ts" title="app/phone-detail/phone-detail.component.ts"> <code-example path="upgrade-phonecat-3-final/app/phone-detail/phone-detail.component.ts" header="app/phone-detail/phone-detail.component.ts">
</code-example> </code-example>
You are now running a pure Angular application! You are now running a pure Angular application!
@ -1677,7 +1677,7 @@ There's no need for that anymore.
Switch the bootstrap method of the application from the `UpgradeModule` to the Angular way. Switch the bootstrap method of the application from the `UpgradeModule` to the Angular way.
<code-example path="upgrade-phonecat-3-final/app/main.ts" title="main.ts"> <code-example path="upgrade-phonecat-3-final/app/main.ts" header="main.ts">
</code-example> </code-example>
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`,
@ -1689,7 +1689,7 @@ together with the associated AngularJS factory or directive declarations.
Since you no longer have downgraded components, you no longer list them Since you no longer have downgraded components, you no longer list them
in `entryComponents`. in `entryComponents`.
<code-example path="upgrade-phonecat-3-final/app/app.module.ts" title="app.module.ts"> <code-example path="upgrade-phonecat-3-final/app/app.module.ts" header="app.module.ts">
</code-example> </code-example>
You may also completely remove the following files. They are AngularJS You may also completely remove the following files. They are AngularJS
@ -1714,7 +1714,7 @@ The `@angular/upgrade` package and its mapping in `systemjs.config.js` can also
Finally, from `index.html`, remove all references to AngularJS scripts and jQuery. Finally, from `index.html`, remove all references to AngularJS scripts and jQuery.
When you're done, this is what it should look like: When you're done, this is what it should look like:
<code-example path="upgrade-phonecat-3-final/index.html" region="full" title="index.html"> <code-example path="upgrade-phonecat-3-final/index.html" region="full" header="index.html">
</code-example> </code-example>
That is the last you'll see of AngularJS! It has served us well but now That is the last you'll see of AngularJS! It has served us well but now
@ -1869,12 +1869,12 @@ service is no longer present after the upgrade, replace those calls with ones
that use WebDriver's generic URL APIs instead. The first of these is that use WebDriver's generic URL APIs instead. The first of these is
the redirection spec: the redirection spec:
<code-example path="upgrade-phonecat-3-final/e2e-spec.ts" region="redirect" title="e2e-tests/scenarios.ts"> <code-example path="upgrade-phonecat-3-final/e2e-spec.ts" region="redirect" header="e2e-tests/scenarios.ts">
</code-example> </code-example>
And the second is the phone links spec: And the second is the phone links spec:
<code-example path="upgrade-phonecat-3-final/e2e-spec.ts" region="links" title="e2e-tests/scenarios.ts"> <code-example path="upgrade-phonecat-3-final/e2e-spec.ts" region="links" header="e2e-tests/scenarios.ts">
</code-example> </code-example>
### Unit Tests ### Unit Tests
@ -1889,14 +1889,14 @@ For instance, in the phone detail component spec, you can use ES2015
features like arrow functions and block-scoped variables and benefit from the type features like arrow functions and block-scoped variables and benefit from the type
definitions of the AngularJS services you're consuming: definitions of the AngularJS services you're consuming:
<code-example path="upgrade-phonecat-1-typescript/app/phone-detail/phone-detail.component.spec.ts" title="app/phone-detail/phone-detail.component.spec.ts"> <code-example path="upgrade-phonecat-1-typescript/app/phone-detail/phone-detail.component.spec.ts" header="app/phone-detail/phone-detail.component.spec.ts">
</code-example> </code-example>
Once you start the upgrade process and bring in SystemJS, configuration changes Once you start the upgrade process and bring in SystemJS, configuration changes
are needed for Karma. You need to let SystemJS load all the new Angular code, are needed for Karma. You need to let SystemJS load all the new Angular code,
which can be done with the following kind of shim file: which can be done with the following kind of shim file:
<code-example path="upgrade-phonecat-2-hybrid/karma-test-shim.1.js" title="karma-test-shim.js"> <code-example path="upgrade-phonecat-2-hybrid/karma-test-shim.1.js" header="karma-test-shim.js">
</code-example> </code-example>
The shim first loads the SystemJS configuration, then Angular's test support libraries, The shim first loads the SystemJS configuration, then Angular's test support libraries,
@ -1905,53 +1905,53 @@ and then the application's spec files themselves.
Karma configuration should then be changed so that it uses the application root dir Karma configuration should then be changed so that it uses the application root dir
as the base directory, instead of `app`. as the base directory, instead of `app`.
<code-example path="upgrade-phonecat-2-hybrid/karma.conf.ajs.js" region="basepath" title="karma.conf.js"> <code-example path="upgrade-phonecat-2-hybrid/karma.conf.ajs.js" region="basepath" header="karma.conf.js">
</code-example> </code-example>
Once done, you can load SystemJS and other dependencies, and also switch the configuration Once done, you can load SystemJS and other dependencies, and also switch the configuration
for loading application files so that they are *not* included to the page by Karma. You'll let for loading application files so that they are *not* included to the page by Karma. You'll let
the shim and SystemJS load them. the shim and SystemJS load them.
<code-example path="upgrade-phonecat-2-hybrid/karma.conf.ajs.js" region="files" title="karma.conf.js"> <code-example path="upgrade-phonecat-2-hybrid/karma.conf.ajs.js" region="files" header="karma.conf.js">
</code-example> </code-example>
Since the HTML templates of Angular components will be loaded as well, you must help Since the HTML templates of Angular components will be loaded as well, you must help
Karma out a bit so that it can route them to the right paths: Karma out a bit so that it can route them to the right paths:
<code-example path="upgrade-phonecat-2-hybrid/karma.conf.ajs.js" region="html" title="karma.conf.js"> <code-example path="upgrade-phonecat-2-hybrid/karma.conf.ajs.js" region="html" header="karma.conf.js">
</code-example> </code-example>
The unit test files themselves also need to be switched to Angular when their production The unit test files themselves also need to be switched to Angular when their production
counterparts are switched. The specs for the checkmark pipe are probably the most straightforward, counterparts are switched. The specs for the checkmark pipe are probably the most straightforward,
as the pipe has no dependencies: as the pipe has no dependencies:
<code-example path="upgrade-phonecat-2-hybrid/app/core/checkmark/checkmark.pipe.spec.ts" title="app/core/checkmark/checkmark.pipe.spec.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/core/checkmark/checkmark.pipe.spec.ts" header="app/core/checkmark/checkmark.pipe.spec.ts">
</code-example> </code-example>
The unit test for the phone service is a bit more involved. You need to switch from the mocked-out The unit test for the phone service is a bit more involved. You need to switch from the mocked-out
AngularJS `$httpBackend` to a mocked-out Angular Http backend. AngularJS `$httpBackend` to a mocked-out Angular Http backend.
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.spec.ts" title="app/core/phone/phone.service.spec.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.spec.ts" header="app/core/phone/phone.service.spec.ts">
</code-example> </code-example>
For the component specs, you can mock out the `Phone` service itself, and have it provide For the component specs, you can mock out the `Phone` service itself, and have it provide
canned phone data. You use Angular's component unit testing APIs for both components. canned phone data. You use Angular's component unit testing APIs for both components.
<code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.component.spec.ts" title="app/phone-detail/phone-detail.component.spec.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.component.spec.ts" header="app/phone-detail/phone-detail.component.spec.ts">
</code-example> </code-example>
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.spec.ts" title="app/phone-list/phone-list.component.spec.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.spec.ts" header="app/phone-list/phone-list.component.spec.ts">
</code-example> </code-example>
Finally, revisit both of the component tests when you switch to the Angular Finally, revisit both of the component tests when you switch to the Angular
router. For the details component, provide a mock of Angular `ActivatedRoute` object router. For the details component, provide a mock of Angular `ActivatedRoute` object
instead of using the AngularJS `$routeParams`. instead of using the AngularJS `$routeParams`.
<code-example path="upgrade-phonecat-3-final/app/phone-detail/phone-detail.component.spec.ts" region="activatedroute" title="app/phone-detail/phone-detail.component.spec.ts"> <code-example path="upgrade-phonecat-3-final/app/phone-detail/phone-detail.component.spec.ts" region="activatedroute" header="app/phone-detail/phone-detail.component.spec.ts">
</code-example> </code-example>
And for the phone list component, a few adjustments to the router make And for the phone list component, a few adjustments to the router make
the `RouteLink` directives work. the `RouteLink` directives work.
<code-example path="upgrade-phonecat-3-final/app/phone-list/phone-list.component.spec.ts" region="routestuff" title="app/phone-list/phone-list.component.spec.ts"> <code-example path="upgrade-phonecat-3-final/app/phone-list/phone-list.component.spec.ts" region="routestuff" header="app/phone-list/phone-list.component.spec.ts">
</code-example> </code-example>

View File

@ -20,7 +20,7 @@ To bind to a DOM event, surround the DOM event name in parentheses and assign a
The following example shows an event binding that implements a click handler: The following example shows an event binding that implements a click handler:
<code-example path="user-input/src/app/click-me.component.ts" region="click-me-button" title="src/app/click-me.component.ts" linenums="false"> <code-example path="user-input/src/app/click-me.component.ts" region="click-me-button" header="src/app/click-me.component.ts" linenums="false">
</code-example> </code-example>
@ -37,7 +37,7 @@ usually the Angular component controlling the template.
The example above shows a single line of HTML, but that HTML belongs to a larger component: The example above shows a single line of HTML, but that HTML belongs to a larger component:
<code-example path="user-input/src/app/click-me.component.ts" region="click-me-component" title="src/app/click-me.component.ts" linenums="false"> <code-example path="user-input/src/app/click-me.component.ts" region="click-me-component" header="src/app/click-me.component.ts" linenums="false">
</code-example> </code-example>
@ -53,7 +53,7 @@ This section shows how to bind to the `keyup` event of an input box to get the u
The following code listens to the `keyup` event and passes the entire event payload (`$event`) to the component event handler. The following code listens to the `keyup` event and passes the entire event payload (`$event`) to the component event handler.
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-1-template" title="src/app/keyup.components.ts (template v.1)" linenums="false"> <code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-1-template" header="src/app/keyup.components.ts (template v.1)" linenums="false">
</code-example> </code-example>
@ -62,7 +62,7 @@ The following code listens to the `keyup` event and passes the entire event payl
When a user presses and releases a key, the `keyup` event occurs, and Angular provides a corresponding When a user presses and releases a key, the `keyup` event occurs, and Angular provides a corresponding
DOM event object in the `$event` variable which this code passes as a parameter to the component's `onKey()` method. DOM event object in the `$event` variable which this code passes as a parameter to the component's `onKey()` method.
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-1-class-no-type" title="src/app/keyup.components.ts (class v.1)" linenums="false"> <code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-1-class-no-type" header="src/app/keyup.components.ts (class v.1)" linenums="false">
</code-example> </code-example>
@ -126,7 +126,7 @@ that could reveal properties of the event object and prevent silly mistakes.
The following example rewrites the method with types: The following example rewrites the method with types:
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-1-class" title="src/app/keyup.components.ts (class v.1 - typed )" linenums="false"> <code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-1-class" header="src/app/keyup.components.ts (class v.1 - typed )" linenums="false">
</code-example> </code-example>
@ -156,7 +156,7 @@ To declare a template reference variable, precede an identifier with a hash (or
The following example uses a template reference variable The following example uses a template reference variable
to implement a keystroke loopback in a simple template. to implement a keystroke loopback in a simple template.
<code-example path="user-input/src/app/loop-back.component.ts" region="loop-back-component" title="src/app/loop-back.component.ts" linenums="false"> <code-example path="user-input/src/app/loop-back.component.ts" region="loop-back-component" header="src/app/loop-back.component.ts" linenums="false">
</code-example> </code-example>
@ -200,7 +200,7 @@ It's easier to get to the input box with the template reference
variable than to go through the `$event` object. Here's a rewrite of the previous variable than to go through the `$event` object. Here's a rewrite of the previous
`keyup` example that uses a template reference variable to get the user's input. `keyup` example that uses a template reference variable to get the user's input.
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-2" title="src/app/keyup.components.ts (v2)" linenums="false"> <code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-2" header="src/app/keyup.components.ts (v2)" linenums="false">
</code-example> </code-example>
@ -219,7 +219,7 @@ One way to reduce the noise would be to examine every `$event.keyCode` and take
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" header="src/app/keyup.components.ts (v3)" linenums="false">
</code-example> </code-example>
@ -244,7 +244,7 @@ The component's `value` property is updated only when the user presses _Enter_.
To fix this issue, listen to both the _Enter_ key and the _blur_ event. To fix this issue, listen to both the _Enter_ key and the _blur_ event.
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-4" title="src/app/keyup.components.ts (v4)" linenums="false"> <code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-4" header="src/app/keyup.components.ts (v4)" linenums="false">
</code-example> </code-example>
@ -270,7 +270,7 @@ clicking **Add**.
Below is the "Little Tour of Heroes" component. Below is the "Little Tour of Heroes" component.
<code-example path="user-input/src/app/little-tour.component.ts" region="little-tour" title="src/app/little-tour.component.ts" linenums="false"> <code-example path="user-input/src/app/little-tour.component.ts" region="little-tour" header="src/app/little-tour.component.ts" linenums="false">
</code-example> </code-example>
@ -299,19 +299,19 @@ Following is all the code discussed in this page.
<code-tabs> <code-tabs>
<code-pane title="click-me.component.ts" path="user-input/src/app/click-me.component.ts"> <code-pane header="click-me.component.ts" path="user-input/src/app/click-me.component.ts">
</code-pane> </code-pane>
<code-pane title="keyup.components.ts" path="user-input/src/app/keyup.components.ts"> <code-pane header="keyup.components.ts" path="user-input/src/app/keyup.components.ts">
</code-pane> </code-pane>
<code-pane title="loop-back.component.ts" path="user-input/src/app/loop-back.component.ts"> <code-pane header="loop-back.component.ts" path="user-input/src/app/loop-back.component.ts">
</code-pane> </code-pane>
<code-pane title="little-tour.component.ts" path="user-input/src/app/little-tour.component.ts"> <code-pane header="little-tour.component.ts" path="user-input/src/app/little-tour.component.ts">
</code-pane> </code-pane>

View File

@ -6,37 +6,37 @@
<p>No linenums at code-tabs level</p> <p>No linenums at code-tabs level</p>
<code-tabs > <code-tabs >
<code-pane title='TS code file' language='ts'> <code-pane header='TS code file' language='ts'>
class { class {
foo(param: string) {} foo(param: string) {}
} }
</code-pane> </code-pane>
<code-pane title='HTML content file' language='html'>&lt;h1&gt;Heading&lt;/h1&gt;</code-pane> <code-pane header='HTML content file' language='html'>&lt;h1&gt;Heading&lt;/h1&gt;</code-pane>
<code-pane title='JSON data file' language='json' class='avoid'>{ "key": "value" }</code-pane> <code-pane header='JSON data file' language='json' class='avoid'>{ "key": "value" }</code-pane>
</code-tabs> </code-tabs>
<p></p> <p></p>
<p>linenums=true at code-tabs level</p> <p>linenums=true at code-tabs level</p>
<code-tabs linenums='true'> <code-tabs linenums='true'>
<code-pane title='TS code file' language='ts'> <code-pane header='TS code file' language='ts'>
class { class {
foo(param: string) {} foo(param: string) {}
} }
</code-pane> </code-pane>
<code-pane title='HTML content file' language='html'>&lt;h1&gt;Heading&lt;/h1&gt;</code-pane> <code-pane header='HTML content file' language='html'>&lt;h1&gt;Heading&lt;/h1&gt;</code-pane>
<code-pane title='JSON data file' language='json' class='avoid'>{ "key": "value" }</code-pane> <code-pane header='JSON data file' language='json' class='avoid'>{ "key": "value" }</code-pane>
</code-tabs> </code-tabs>
<p></p> <p></p>
<p>No linenums at code-tabs level; linenums=true for HTML pane</p> <p>No linenums at code-tabs level; linenums=true for HTML pane</p>
<code-tabs > <code-tabs >
<code-pane title='TS code file' language='ts'> <code-pane header='TS code file' language='ts'>
class { class {
foo(param: string) {} foo(param: string) {}
} }
</code-pane> </code-pane>
<code-pane title='HTML content file' language='html' linenums='true'>&lt;h1&gt;Heading&lt;/h1&gt;</code-pane> <code-pane header='HTML content file' language='html' linenums='true'>&lt;h1&gt;Heading&lt;/h1&gt;</code-pane>
<code-pane title='JSON data file' language='json' class='avoid'>{ "key": "value" }</code-pane> <code-pane header='JSON data file' language='json' class='avoid'>{ "key": "value" }</code-pane>
</code-tabs> </code-tabs>
<p></p> <p></p>
@ -66,7 +66,7 @@
</code-example> </code-example>
<p>Header on this one.</p> <p>Header on this one.</p>
<code-example title="hero-details.component.ts (excerpt)"> <code-example header="hero-details.component.ts (excerpt)">
&lt;hero-details <em>nghost-pmm-5&gt; &lt;hero-details <em>nghost-pmm-5&gt;
&lt;h2 </em>ngcontent-pmm-5&gt;Mister Fantastic&lt;/h2&gt; &lt;h2 </em>ngcontent-pmm-5&gt;Mister Fantastic&lt;/h2&gt;
&lt;hero-team <em>ngcontent-pmm-5 </em>nghost-pmm-6&gt; &lt;hero-team <em>ngcontent-pmm-5 </em>nghost-pmm-6&gt;
@ -76,7 +76,7 @@
</code-example> </code-example>
<p>An "avoid" header on this one.</p> <p>An "avoid" header on this one.</p>
<code-example class="avoid" title="hero-details.component.ts (Avoid)"> <code-example class="avoid" header="hero-details.component.ts (Avoid)">
&lt;hero-details <em>nghost-pmm-5&gt; &lt;hero-details <em>nghost-pmm-5&gt;
&lt;h2 </em>ngcontent-pmm-5&gt;Mister Fantastic&lt;/h2&gt; &lt;h2 </em>ngcontent-pmm-5&gt;Mister Fantastic&lt;/h2&gt;
&lt;hero-team <em>ngcontent-pmm-5 </em>nghost-pmm-6&gt; &lt;hero-team <em>ngcontent-pmm-5 </em>nghost-pmm-6&gt;

View File

@ -91,7 +91,7 @@ You'll find the implementation of the shell `AppComponent` distributed over thre
Open the component class file (`app.component.ts`) and change the value of the `title` property to 'Tour of Heroes'. Open the component class file (`app.component.ts`) and change the value of the `title` property to 'Tour of Heroes'.
<code-example path="toh-pt0/src/app/app.component.ts" region="set-title" title="app.component.ts (class title property)" linenums="false"> <code-example path="toh-pt0/src/app/app.component.ts" region="set-title" header="app.component.ts (class title property)" linenums="false">
</code-example> </code-example>
Open the component template file (`app.component.html`) and Open the component template file (`app.component.html`) and
@ -99,7 +99,7 @@ delete the default template generated by the Angular CLI.
Replace it with the following line of HTML. Replace it with the following line of HTML.
<code-example path="toh-pt0/src/app/app.component.html" <code-example path="toh-pt0/src/app/app.component.html"
title="app.component.html (template)" linenums="false"> header="app.component.html (template)" linenums="false">
</code-example> </code-example>
The double curly braces are Angular's *interpolation binding* syntax. The double curly braces are Angular's *interpolation binding* syntax.
@ -118,7 +118,7 @@ Put your application-wide styles there.
Here's an excerpt from the `styles.css` for the _Tour of Heroes_ sample app. Here's an excerpt from the `styles.css` for the _Tour of Heroes_ sample app.
<code-example path="toh-pt0/src/styles.1.css" title="src/styles.css (excerpt)"> <code-example path="toh-pt0/src/styles.1.css" header="src/styles.css (excerpt)">
</code-example> </code-example>
## Final code review ## Final code review
@ -130,14 +130,14 @@ Here are the code files discussed on this page.
<code-tabs> <code-tabs>
<code-pane title="src/app/app.component.ts" path="toh-pt0/src/app/app.component.ts"> <code-pane header="src/app/app.component.ts" path="toh-pt0/src/app/app.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/app.component.html" path="toh-pt0/src/app/app.component.html"> <code-pane header="src/app/app.component.html" path="toh-pt0/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="src/styles.css (excerpt)" header="src/styles.css (excerpt)"
path="toh-pt0/src/styles.1.css"> path="toh-pt0/src/styles.1.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>

View File

@ -19,7 +19,7 @@ The `HeroesComponent` class file is as follows:
<code-example <code-example
path="toh-pt1/src/app/heroes/heroes.component.ts" region="v1" path="toh-pt1/src/app/heroes/heroes.component.ts" region="v1"
title="app/heroes/heroes.component.ts (initial version)" linenums="false"> header="app/heroes/heroes.component.ts (initial version)" linenums="false">
</code-example> </code-example>
You always import the `Component` symbol from the Angular core library You always import the `Component` symbol from the Angular core library
@ -48,7 +48,7 @@ Always `export` the component class so you can `import` it elsewhere ... like in
Add a `hero` property to the `HeroesComponent` for a hero named "Windstorm." Add a `hero` property to the `HeroesComponent` for a hero named "Windstorm."
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" region="add-hero" title="heroes.component.ts (hero property)" linenums="false"> <code-example path="toh-pt1/src/app/heroes/heroes.component.ts" region="add-hero" header="heroes.component.ts (hero property)" linenums="false">
</code-example> </code-example>
### Show the hero ### Show the hero
@ -57,7 +57,7 @@ Open the `heroes.component.html` template file.
Delete the default text generated by the Angular CLI and Delete the default text generated by the Angular CLI and
replace it with a data binding to the new `hero` property. replace it with a data binding to the new `hero` property.
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" title="heroes.component.html" region="show-hero-1" linenums="false"> <code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" header="heroes.component.html" region="show-hero-1" linenums="false">
</code-example> </code-example>
## Show the _HeroesComponent_ view ## Show the _HeroesComponent_ view
@ -67,7 +67,7 @@ To display the `HeroesComponent`, you must add it to the template of the shell `
Remember that `app-heroes` is the [element selector](#selector) for the `HeroesComponent`. Remember that `app-heroes` is the [element selector](#selector) for the `HeroesComponent`.
So add an `<app-heroes>` element to the `AppComponent` template file, just below the title. So add an `<app-heroes>` element to the `AppComponent` template file, just below the title.
<code-example path="toh-pt1/src/app/app.component.html" title="src/app/app.component.html" linenums="false"> <code-example path="toh-pt1/src/app/app.component.html" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Assuming that the CLI `ng serve` command is still running, Assuming that the CLI `ng serve` command is still running,
@ -80,7 +80,7 @@ A real hero is more than a name.
Create a `Hero` class in its own file in the `src/app` folder. Create a `Hero` class in its own file in the `src/app` folder.
Give it `id` and `name` properties. Give it `id` and `name` properties.
<code-example path="toh-pt1/src/app/hero.ts" title="src/app/hero.ts" linenums="false"> <code-example path="toh-pt1/src/app/hero.ts" header="src/app/hero.ts" linenums="false">
</code-example> </code-example>
@ -92,7 +92,7 @@ Initialize it with an `id` of `1` and the name `Windstorm`.
The revised `HeroesComponent` class file should look like this: The revised `HeroesComponent` class file should look like this:
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" linenums="false" <code-example path="toh-pt1/src/app/heroes/heroes.component.ts" linenums="false"
title= "src/app/heroes/heroes.component.ts"> header= "src/app/heroes/heroes.component.ts">
</code-example> </code-example>
The page no longer displays properly because you changed the hero from a string to an object. The page no longer displays properly because you changed the hero from a string to an object.
@ -105,7 +105,7 @@ and show both `id` and `name` in a details layout like this:
<code-example <code-example
path="toh-pt1/src/app/heroes/heroes.component.1.html" path="toh-pt1/src/app/heroes/heroes.component.1.html"
region="show-hero-2" region="show-hero-2"
title="heroes.component.html (HeroesComponent's template)" linenums="false"> header="heroes.component.html (HeroesComponent's template)" linenums="false">
</code-example> </code-example>
The browser refreshes and displays the hero's information. The browser refreshes and displays the hero's information.
@ -142,7 +142,7 @@ To automate that data flow, setup a two-way data binding between the `<input>` f
Refactor the details area in the `HeroesComponent` template so it looks like this: Refactor the details area in the `HeroesComponent` template so it looks like this:
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" region="name-input" title="src/app/heroes/heroes.component.html (HeroesComponent's template)" linenums="false"> <code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" region="name-input" header="src/app/heroes/heroes.component.html (HeroesComponent's template)" linenums="false">
</code-example> </code-example>
@ -184,13 +184,13 @@ This is where you _opt-in_ to the `FormsModule`.
Open `AppModule` (`app.module.ts`) and import the `FormsModule` symbol from the `@angular/forms` library. Open `AppModule` (`app.module.ts`) and import the `FormsModule` symbol from the `@angular/forms` library.
<code-example path="toh-pt1/src/app/app.module.ts" title="app.module.ts (FormsModule symbol import)" <code-example path="toh-pt1/src/app/app.module.ts" header="app.module.ts (FormsModule symbol import)"
region="formsmodule-js-import"> region="formsmodule-js-import">
</code-example> </code-example>
Then add `FormsModule` to the `@NgModule` metadata's `imports` array, which contains a list of external modules that the app needs. Then add `FormsModule` to the `@NgModule` metadata's `imports` array, which contains a list of external modules that the app needs.
<code-example path="toh-pt1/src/app/app.module.ts" title="app.module.ts ( @NgModule imports)" <code-example path="toh-pt1/src/app/app.module.ts" header="app.module.ts ( @NgModule imports)"
region="ng-imports"> region="ng-imports">
</code-example> </code-example>
@ -222,23 +222,23 @@ Your app should look like this <live-example></live-example>. Here are the code
<code-tabs> <code-tabs>
<code-pane title="src/app/heroes/heroes.component.ts" path="toh-pt1/src/app/heroes/heroes.component.ts"> <code-pane header="src/app/heroes/heroes.component.ts" path="toh-pt1/src/app/heroes/heroes.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/heroes.component.html" path="toh-pt1/src/app/heroes/heroes.component.html"> <code-pane header="src/app/heroes/heroes.component.html" path="toh-pt1/src/app/heroes/heroes.component.html">
</code-pane> </code-pane>
<code-pane title="src/app/app.module.ts" <code-pane header="src/app/app.module.ts"
path="toh-pt1/src/app/app.module.ts"> path="toh-pt1/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="src/app/app.component.ts" path="toh-pt1/src/app/app.component.ts"> <code-pane header="src/app/app.component.ts" path="toh-pt1/src/app/app.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/app.component.html" path="toh-pt1/src/app/app.component.html"> <code-pane header="src/app/app.component.html" path="toh-pt1/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane title="src/app/hero.ts" <code-pane header="src/app/hero.ts"
path="toh-pt1/src/app/hero.ts"> path="toh-pt1/src/app/hero.ts">
</code-pane> </code-pane>

View File

@ -16,7 +16,7 @@ Define a `HEROES` constant as an array of ten heroes and export it.
The file should look like this. The file should look like this.
<code-example path="toh-pt2/src/app/mock-heroes.ts" linenums="false" <code-example path="toh-pt2/src/app/mock-heroes.ts" linenums="false"
title="src/app/mock-heroes.ts"> header="src/app/mock-heroes.ts">
</code-example> </code-example>
## Displaying heroes ## Displaying heroes
@ -25,7 +25,7 @@ You're about to display the list of heroes at the top of the `HeroesComponent`.
Open the `HeroesComponent` class file and import the mock `HEROES`. Open the `HeroesComponent` class file and import the mock `HEROES`.
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="import-heroes" title="src/app/heroes/heroes.component.ts (import HEROES)"> <code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="import-heroes" header="src/app/heroes/heroes.component.ts (import HEROES)">
</code-example> </code-example>
In the same file (`HeroesComponent` class), define a component property called `heroes` to expose `HEROES` array for binding. In the same file (`HeroesComponent` class), define a component property called `heroes` to expose `HEROES` array for binding.
@ -44,7 +44,7 @@ Open the `HeroesComponent` template file and make the following changes:
Make it look like this: Make it look like this:
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="list" title="heroes.component.html (heroes template)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="list" header="heroes.component.html (heroes template)" linenums="false">
</code-example> </code-example>
Now change the `<li>` to this: Now change the `<li>` to this:
@ -94,7 +94,7 @@ When the CLI generated the `HeroesComponent`, it created an empty `heroes.compon
and pointed to it in `@Component.styleUrls` like this. and pointed to it in `@Component.styleUrls` like this.
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="metadata" <code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="metadata"
title="src/app/heroes/heroes.component.ts (@Component)"> header="src/app/heroes/heroes.component.ts (@Component)">
</code-example> </code-example>
Open the `heroes.component.css` file and paste in the private CSS styles for the `HeroesComponent`. Open the `heroes.component.css` file and paste in the private CSS styles for the `HeroesComponent`.
@ -119,7 +119,7 @@ and update the hero detail.
Add a click event binding to the `<li>` like this: Add a click event binding to the `<li>` like this:
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="selectedHero-click" title="heroes.component.html (template excerpt)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="selectedHero-click" header="heroes.component.html (template excerpt)" linenums="false">
</code-example> </code-example>
This is an example of Angular's [event binding](guide/template-syntax#event-binding) syntax. This is an example of Angular's [event binding](guide/template-syntax#event-binding) syntax.
@ -139,7 +139,7 @@ There is no _selected hero_ when the application starts.
Add the following `onSelect()` method, which assigns the clicked hero from the template Add the following `onSelect()` method, which assigns the clicked hero from the template
to the component's `selectedHero`. to the component's `selectedHero`.
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="on-select" title="src/app/heroes/heroes.component.ts (onSelect)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="on-select" header="src/app/heroes/heroes.component.ts (onSelect)" linenums="false">
</code-example> </code-example>
### Update the details template ### Update the details template
@ -147,7 +147,7 @@ to the component's `selectedHero`.
The template still refers to the component's old `hero` property which no longer exists. The template still refers to the component's old `hero` property which no longer exists.
Rename `hero` to `selectedHero`. Rename `hero` to `selectedHero`.
<code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="selectedHero-details" title="heroes.component.html (selected hero details)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="selectedHero-details" header="heroes.component.html (selected hero details)" linenums="false">
</code-example> </code-example>
### Hide empty details with _*ngIf_ ### Hide empty details with _*ngIf_
@ -183,7 +183,7 @@ Don't forget the asterisk (*) in front of `ngIf`. It's a critical part of the sy
</div> </div>
<code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="ng-if" title="src/app/heroes/heroes.component.html (*ngIf)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="ng-if" header="src/app/heroes/heroes.component.html (*ngIf)" linenums="false">
</code-example> </code-example>
After the browser refreshes, the list of names reappears. After the browser refreshes, the list of names reappears.
@ -217,14 +217,14 @@ Just add `[class.some-css-class]="some-condition"` to the element you want to st
Add the following `[class.selected]` binding to the `<li>` in the `HeroesComponent` template: Add the following `[class.selected]` binding to the `<li>` in the `HeroesComponent` template:
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="class-selected" title="heroes.component.html (toggle the 'selected' CSS class)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="class-selected" header="heroes.component.html (toggle the 'selected' CSS class)" linenums="false">
</code-example> </code-example>
When the current row hero is the same as the `selectedHero`, Angular adds the `selected` CSS class. When the two heroes are different, Angular removes the class. When the current row hero is the same as the `selectedHero`, Angular adds the `selected` CSS class. When the two heroes are different, Angular removes the class.
The finished `<li>` looks like this: The finished `<li>` looks like this:
<code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="li" title="heroes.component.html (list item hero)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="li" header="heroes.component.html (list item hero)" linenums="false">
</code-example> </code-example>
@ -237,13 +237,13 @@ Your app should look like this <live-example></live-example>.
Here are the code files discussed on this page, including the `HeroesComponent` styles. Here are the code files discussed on this page, including the `HeroesComponent` styles.
<code-tabs> <code-tabs>
<code-pane title="src/app/heroes/heroes.component.ts" path="toh-pt2/src/app/heroes/heroes.component.ts"> <code-pane header="src/app/heroes/heroes.component.ts" path="toh-pt2/src/app/heroes/heroes.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/heroes.component.html" path="toh-pt2/src/app/heroes/heroes.component.html"> <code-pane header="src/app/heroes/heroes.component.html" path="toh-pt2/src/app/heroes/heroes.component.html">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/heroes.component.css" path="toh-pt2/src/app/heroes/heroes.component.css"> <code-pane header="src/app/heroes/heroes.component.css" path="toh-pt2/src/app/heroes/heroes.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>

View File

@ -42,7 +42,7 @@ So replace "selectedHero" with "hero" everywhere in the template.
When you're done, the `HeroDetailComponent` template should look like this: When you're done, the `HeroDetailComponent` template should look like this:
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.html" title="src/app/hero-detail/hero-detail.component.html" linenums="false"> <code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.html" header="src/app/hero-detail/hero-detail.component.html" linenums="false">
</code-example> </code-example>
@ -54,7 +54,7 @@ which is of type `Hero`.
Open the `HeroDetailComponent` class file and import the `Hero` symbol. Open the `HeroDetailComponent` class file and import the `Hero` symbol.
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" <code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts"
region="import-hero" title="src/app/hero-detail/hero-detail.component.ts (import Hero)"> region="import-hero" header="src/app/hero-detail/hero-detail.component.ts (import Hero)">
</code-example> </code-example>
The `hero` property The `hero` property
@ -67,7 +67,7 @@ because the _external_ `HeroesComponent` [will bind to it](#heroes-component-tem
Amend the `@angular/core` import statement to include the `Input` symbol. Amend the `@angular/core` import statement to include the `Input` symbol.
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" region="import-input" title="src/app/hero-detail/hero-detail.component.ts (import Input)" linenums="false"> <code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" region="import-input" header="src/app/hero-detail/hero-detail.component.ts (import Input)" linenums="false">
</code-example> </code-example>
Add a `hero` property, preceded by the `@Input()` decorator. Add a `hero` property, preceded by the `@Input()` decorator.
@ -101,7 +101,7 @@ Add an `<app-hero-detail>` element near the bottom of the `HeroesComponent` temp
Bind the `HeroesComponent.selectedHero` to the element's `hero` property like this. Bind the `HeroesComponent.selectedHero` to the element's `hero` property like this.
<code-example path="toh-pt3/src/app/heroes/heroes.component.html" region="hero-detail-binding" title="heroes.component.html (HeroDetail binding)"> <code-example path="toh-pt3/src/app/heroes/heroes.component.html" region="hero-detail-binding" header="heroes.component.html (HeroDetail binding)">
</code-example> </code-example>
@ -117,7 +117,7 @@ and the `HeroDetailComponent` displays the new hero.
The revised `HeroesComponent` template should look like this: The revised `HeroesComponent` template should look like this:
<code-example path="toh-pt3/src/app/heroes/heroes.component.html" <code-example path="toh-pt3/src/app/heroes/heroes.component.html"
title="heroes.component.html" linenums="false"> header="heroes.component.html" linenums="false">
</code-example> </code-example>
The browser refreshes and the app starts working again as it did before. The browser refreshes and the app starts working again as it did before.
@ -145,16 +145,16 @@ Here are the code files discussed on this page and your app should look like thi
<code-tabs> <code-tabs>
<code-pane title="src/app/hero-detail/hero-detail.component.ts" path="toh-pt3/src/app/hero-detail/hero-detail.component.ts"> <code-pane header="src/app/hero-detail/hero-detail.component.ts" path="toh-pt3/src/app/hero-detail/hero-detail.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/hero-detail/hero-detail.component.html" path="toh-pt3/src/app/hero-detail/hero-detail.component.html"> <code-pane header="src/app/hero-detail/hero-detail.component.html" path="toh-pt3/src/app/hero-detail/hero-detail.component.html">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/heroes.component.html" path="toh-pt3/src/app/heroes/heroes.component.html"> <code-pane header="src/app/heroes/heroes.component.html" path="toh-pt3/src/app/heroes/heroes.component.html">
</code-pane> </code-pane>
<code-pane title="src/app/app.module.ts" path="toh-pt3/src/app/app.module.ts"> <code-pane header="src/app/app.module.ts" path="toh-pt3/src/app/app.module.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>

View File

@ -34,7 +34,7 @@ The command generates skeleton `HeroService` class in `src/app/hero.service.ts`
The `HeroService` class should look like the following example. The `HeroService` class should look like the following example.
<code-example path="toh-pt4/src/app/hero.service.1.ts" region="new" <code-example path="toh-pt4/src/app/hero.service.1.ts" region="new"
title="src/app/hero.service.ts (new service)" linenums="false"> header="src/app/hero.service.ts (new service)" linenums="false">
</code-example> </code-example>
### _@Injectable()_ services ### _@Injectable()_ services
@ -110,7 +110,7 @@ Open the `HeroesComponent` class file.
Delete the `HEROES` import, because you won't need that anymore. Delete the `HEROES` import, because you won't need that anymore.
Import the `HeroService` instead. Import the `HeroService` instead.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" title="src/app/heroes/heroes.component.ts (import HeroService)" region="hero-service-import"> <code-example path="toh-pt4/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts (import HeroService)" region="hero-service-import">
</code-example> </code-example>
Replace the definition of the `heroes` property with a simple declaration. Replace the definition of the `heroes` property with a simple declaration.
@ -197,7 +197,7 @@ In this tutorial, you'll simulate getting data from the server with the RxJS `of
Open the `HeroService` file and import the `Observable` and `of` symbols from RxJS. Open the `HeroService` file and import the `Observable` and `of` symbols from RxJS.
<code-example path="toh-pt4/src/app/hero.service.ts" <code-example path="toh-pt4/src/app/hero.service.ts"
title="src/app/hero.service.ts (Observable imports)" region="import-observable"> header="src/app/hero.service.ts (Observable imports)" region="import-observable">
</code-example> </code-example>
Replace the `getHeroes` method with this one. Replace the `getHeroes` method with this one.
@ -224,11 +224,11 @@ Find the `getHeroes` method and replace it with the following code
<code-tabs> <code-tabs>
<code-pane title="heroes.component.ts (Observable)" <code-pane header="heroes.component.ts (Observable)"
path="toh-pt4/src/app/heroes/heroes.component.ts" region="getHeroes"> path="toh-pt4/src/app/heroes/heroes.component.ts" region="getHeroes">
</code-pane> </code-pane>
<code-pane title="heroes.component.ts (Original)" <code-pane header="heroes.component.ts (Original)"
path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="getHeroes"> path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="getHeroes">
</code-pane> </code-pane>
@ -272,7 +272,7 @@ The CLI creates the component files in the `src/app/messages` folder and declare
Modify the `AppComponent` template to display the generated `MessagesComponent` Modify the `AppComponent` template to display the generated `MessagesComponent`
<code-example <code-example
title = "/src/app/app.component.html" header = "/src/app/app.component.html"
path="toh-pt4/src/app/app.component.html"> path="toh-pt4/src/app/app.component.html">
</code-example> </code-example>
@ -289,7 +289,7 @@ Use the CLI to create the `MessageService` in `src/app`.
Open `MessageService` and replace its contents with the following. Open `MessageService` and replace its contents with the following.
<code-example <code-example
title = "/src/app/message.service.ts" header = "/src/app/message.service.ts"
path="toh-pt4/src/app/message.service.ts"> path="toh-pt4/src/app/message.service.ts">
</code-example> </code-example>
@ -301,7 +301,7 @@ The service exposes its cache of `messages` and two methods: one to `add()` a me
Re-open the `HeroService` and import the `MessageService`. Re-open the `HeroService` and import the `MessageService`.
<code-example <code-example
title = "/src/app/hero.service.ts (import MessageService)" header = "/src/app/hero.service.ts (import MessageService)"
path="toh-pt4/src/app/hero.service.ts" region="import-message-service"> path="toh-pt4/src/app/hero.service.ts" region="import-message-service">
</code-example> </code-example>
@ -335,7 +335,7 @@ including the message sent by the `HeroService` when it fetches heroes.
Open `MessagesComponent` and import the `MessageService`. Open `MessagesComponent` and import the `MessageService`.
<code-example <code-example
title = "/src/app/messages/messages.component.ts (import MessageService)" header = "/src/app/messages/messages.component.ts (import MessageService)"
path="toh-pt4/src/app/messages/messages.component.ts" region="import-message-service"> path="toh-pt4/src/app/messages/messages.component.ts" region="import-message-service">
</code-example> </code-example>
@ -360,7 +360,7 @@ Angular only binds to _public_ component properties.
Replace the CLI-generated `MessagesComponent` template with the following. Replace the CLI-generated `MessagesComponent` template with the following.
<code-example <code-example
title = "src/app/messages/messages.component.html" header = "src/app/messages/messages.component.html"
path="toh-pt4/src/app/messages/messages.component.html"> path="toh-pt4/src/app/messages/messages.component.html">
</code-example> </code-example>
@ -390,35 +390,35 @@ Here are the code files discussed on this page and your app should look like thi
<code-tabs> <code-tabs>
<code-pane title="src/app/hero.service.ts" <code-pane header="src/app/hero.service.ts"
path="toh-pt4/src/app/hero.service.ts"> path="toh-pt4/src/app/hero.service.ts">
</code-pane> </code-pane>
<code-pane title="src/app/message.service.ts" <code-pane header="src/app/message.service.ts"
path="toh-pt4/src/app/message.service.ts"> path="toh-pt4/src/app/message.service.ts">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/heroes.component.ts" <code-pane header="src/app/heroes/heroes.component.ts"
path="toh-pt4/src/app/heroes/heroes.component.ts"> path="toh-pt4/src/app/heroes/heroes.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/messages/messages.component.ts" <code-pane header="src/app/messages/messages.component.ts"
path="toh-pt4/src/app/messages/messages.component.ts"> path="toh-pt4/src/app/messages/messages.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/messages/messages.component.html" <code-pane header="src/app/messages/messages.component.html"
path="toh-pt4/src/app/messages/messages.component.html"> path="toh-pt4/src/app/messages/messages.component.html">
</code-pane> </code-pane>
<code-pane title="src/app/messages/messages.component.css" <code-pane header="src/app/messages/messages.component.css"
path="toh-pt4/src/app/messages/messages.component.css"> path="toh-pt4/src/app/messages/messages.component.css">
</code-pane> </code-pane>
<code-pane title="src/app/app.module.ts" <code-pane header="src/app/app.module.ts"
path="toh-pt4/src/app/app.module.ts"> path="toh-pt4/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="src/app/app.component.html" <code-pane header="src/app/app.component.html"
path="toh-pt4/src/app/app.component.html"> path="toh-pt4/src/app/app.component.html">
</code-pane> </code-pane>

View File

@ -37,7 +37,7 @@ Use the CLI to generate it.
The generated file looks like this: The generated file looks like this:
<code-example path="toh-pt5/src/app/app-routing.module.0.ts" <code-example path="toh-pt5/src/app/app-routing.module.0.ts"
title="src/app/app-routing.module.ts (generated)"> header="src/app/app-routing.module.ts (generated)">
</code-example> </code-example>
You generally don't declare components in a routing module so you can delete the You generally don't declare components in a routing module so you can delete the
@ -54,7 +54,7 @@ in the `AppModule` components that will need them.
<code-example path="toh-pt5/src/app/app-routing.module.ts" <code-example path="toh-pt5/src/app/app-routing.module.ts"
region="v1" region="v1"
title="src/app/app-routing.module.ts (v1)"> header="src/app/app-routing.module.ts (v1)">
</code-example> </code-example>
### Add routes ### Add routes
@ -105,7 +105,7 @@ Open the `AppComponent` template replace the `<app-heroes>` element with a `<rou
<code-example path="toh-pt5/src/app/app.component.html" <code-example path="toh-pt5/src/app/app.component.html"
region="outlet" region="outlet"
title="src/app/app.component.html (router-outlet)"> header="src/app/app.component.html (router-outlet)">
</code-example> </code-example>
You removed `<app-heroes>` because you will only display the `HeroesComponent` when the user navigates to it. You removed `<app-heroes>` because you will only display the `HeroesComponent` when the user navigates to it.
@ -150,7 +150,7 @@ The revised `AppComponent` template looks like this:
<code-example <code-example
path="toh-pt5/src/app/app.component.html" path="toh-pt5/src/app/app.component.html"
region="heroes" region="heroes"
title="src/app/app.component.html (heroes RouterLink)"> header="src/app/app.component.html (heroes RouterLink)">
</code-example> </code-example>
A [`routerLink` attribute](#routerlink) is set to `"/heroes"`, A [`routerLink` attribute](#routerlink) is set to `"/heroes"`,
@ -190,15 +190,15 @@ Replace the default file content in these three files as follows and then return
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.1.html"> header="src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.1.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="src/app/dashboard/dashboard.component.ts" path="toh-pt5/src/app/dashboard/dashboard.component.ts"> header="src/app/dashboard/dashboard.component.ts" path="toh-pt5/src/app/dashboard/dashboard.component.ts">
</code-pane> </code-pane>
<code-pane <code-pane
title="src/app/dashboard/dashboard.component.css" path="toh-pt5/src/app/dashboard/dashboard.component.css"> header="src/app/dashboard/dashboard.component.css" path="toh-pt5/src/app/dashboard/dashboard.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -227,7 +227,7 @@ Import the `DashboardComponent` in the `AppRoutingModule`.
<code-example <code-example
path="toh-pt5/src/app/app-routing.module.ts" path="toh-pt5/src/app/app-routing.module.ts"
region="import-dashboard" region="import-dashboard"
title="src/app/app-routing.module.ts (import DashboardComponent)"> header="src/app/app-routing.module.ts (import DashboardComponent)">
</code-example> </code-example>
Add a route to the `AppRoutingModule.routes` array that matches a path to the `DashboardComponent`. Add a route to the `AppRoutingModule.routes` array that matches a path to the `DashboardComponent`.
@ -262,7 +262,7 @@ navigation area near the top of the page.
Add a dashboard navigation link to the `AppComponent` shell template, just above the *Heroes* link. Add a dashboard navigation link to the `AppComponent` shell template, just above the *Heroes* link.
<code-example path="toh-pt5/src/app/app.component.html" title="src/app/app.component.html"> <code-example path="toh-pt5/src/app/app.component.html" header="src/app/app.component.html">
</code-example> </code-example>
After the browser refreshes you can navigate freely between the two views by clicking the links. After the browser refreshes you can navigate freely between the two views by clicking the links.
@ -304,7 +304,7 @@ Open `AppRoutingModule` and import `HeroDetailComponent`.
<code-example <code-example
path="toh-pt5/src/app/app-routing.module.ts" path="toh-pt5/src/app/app-routing.module.ts"
region="import-herodetail" region="import-herodetail"
title="src/app/app-routing.module.ts (import HeroDetailComponent)"> header="src/app/app-routing.module.ts (import HeroDetailComponent)">
</code-example> </code-example>
Then add a _parameterized_ route to the `AppRoutingModule.routes` array that matches the path pattern to the _hero detail_ view. Then add a _parameterized_ route to the `AppRoutingModule.routes` array that matches the path pattern to the _hero detail_ view.
@ -321,7 +321,7 @@ At this point, all application routes are in place.
<code-example <code-example
path="toh-pt5/src/app/app-routing.module.ts" path="toh-pt5/src/app/app-routing.module.ts"
region="routes" region="routes"
title="src/app/app-routing.module.ts (all routes)"> header="src/app/app-routing.module.ts (all routes)">
</code-example> </code-example>
### `DashboardComponent` hero links ### `DashboardComponent` hero links
@ -334,7 +334,7 @@ fix the dashboard hero links to navigate via the _parameterized_ dashboard route
<code-example <code-example
path="toh-pt5/src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.html"
region="click" region="click"
title="src/app/dashboard/dashboard.component.html (hero links)"> header="src/app/dashboard/dashboard.component.html (hero links)">
</code-example> </code-example>
You're using Angular [interpolation binding](guide/template-syntax#interpolation) within the `*ngFor` repeater You're using Angular [interpolation binding](guide/template-syntax#interpolation) within the `*ngFor` repeater
@ -350,7 +350,7 @@ are bound to the component's `onSelect()` method.
<code-example <code-example
path="toh-pt4/src/app/heroes/heroes.component.html" path="toh-pt4/src/app/heroes/heroes.component.html"
region="list" region="list"
title="src/app/heroes/heroes.component.html (list with onSelect)"> header="src/app/heroes/heroes.component.html (list with onSelect)">
</code-example> </code-example>
Strip the `<li>` back to just its `*ngFor`, Strip the `<li>` back to just its `*ngFor`,
@ -361,7 +361,7 @@ is the same as in the dashboard template
<code-example <code-example
path="toh-pt5/src/app/heroes/heroes.component.html" path="toh-pt5/src/app/heroes/heroes.component.html"
region="list" region="list"
title="src/app/heroes/heroes.component.html (list with links)"> header="src/app/heroes/heroes.component.html (list with links)">
</code-example> </code-example>
You'll have to fix the private stylesheet (`heroes.component.css`) to make You'll have to fix the private stylesheet (`heroes.component.css`) to make
@ -379,7 +379,7 @@ Here's the class after pruning away the dead code.
<code-example <code-example
path="toh-pt5/src/app/heroes/heroes.component.ts" path="toh-pt5/src/app/heroes/heroes.component.ts"
region="class" region="class"
title="src/app/heroes/heroes.component.ts (cleaned up)" linenums="false"> header="src/app/heroes/heroes.component.ts (cleaned up)" linenums="false">
</code-example> </code-example>
## Routable *HeroDetailComponent* ## Routable *HeroDetailComponent*
@ -401,7 +401,7 @@ Add the following imports:
<code-example <code-example
path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" path="toh-pt5/src/app/hero-detail/hero-detail.component.ts"
region="added-imports" region="added-imports"
title="src/app/hero-detail/hero-detail.component.ts"> header="src/app/hero-detail/hero-detail.component.ts">
</code-example> </code-example>
{@a hero-detail-ctor} {@a hero-detail-ctor}
@ -452,7 +452,7 @@ Open `HeroService` and add this `getHero()` method
<code-example <code-example
path="toh-pt5/src/app/hero.service.ts" path="toh-pt5/src/app/hero.service.ts"
region="getHero" region="getHero"
title="src/app/hero.service.ts (getHero)"> header="src/app/hero.service.ts (getHero)">
</code-example> </code-example>
<div class="alert is-important"> <div class="alert is-important">
@ -493,14 +493,14 @@ to the component's `goBack()` method.
<code-example <code-example
path="toh-pt5/src/app/hero-detail/hero-detail.component.html" path="toh-pt5/src/app/hero-detail/hero-detail.component.html"
region="back-button" region="back-button"
title="src/app/hero-detail/hero-detail.component.html (back button)"> header="src/app/hero-detail/hero-detail.component.html (back button)">
</code-example> </code-example>
Add a `goBack()` _method_ to the component class that navigates backward one step Add a `goBack()` _method_ to the component class that navigates backward one step
in the browser's history stack in the browser's history stack
using the `Location` service that you [injected previously](#hero-detail-ctor). using the `Location` service that you [injected previously](#hero-detail-ctor).
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="goBack" title="src/app/hero-detail/hero-detail.component.ts (goBack)"> <code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="goBack" header="src/app/hero-detail/hero-detail.component.ts (goBack)">
</code-example> </code-example>
@ -521,15 +521,15 @@ Here are the code files discussed on this page and your app should look like thi
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/app-routing.module.ts" header="src/app/app-routing.module.ts"
path="toh-pt5/src/app/app-routing.module.ts"> path="toh-pt5/src/app/app-routing.module.ts">
</code-pane> </code-pane>
<code-pane <code-pane
title="src/app/app.module.ts" header="src/app/app.module.ts"
path="toh-pt5/src/app/app.module.ts"> path="toh-pt5/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane <code-pane
title="src/app/hero.service.ts" header="src/app/hero.service.ts"
path="toh-pt5/src/app/hero.service.ts"> path="toh-pt5/src/app/hero.service.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -539,12 +539,12 @@ Here are the code files discussed on this page and your app should look like thi
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/app.component.html" header="src/app/app.component.html"
path="toh-pt5/src/app/app.component.html"> path="toh-pt5/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="src/app/app.component.css" header="src/app/app.component.css"
path="toh-pt5/src/app/app.component.css"> path="toh-pt5/src/app/app.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -554,15 +554,15 @@ Here are the code files discussed on this page and your app should look like thi
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.html"> header="src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="src/app/dashboard/dashboard.component.ts" path="toh-pt5/src/app/dashboard/dashboard.component.ts"> header="src/app/dashboard/dashboard.component.ts" path="toh-pt5/src/app/dashboard/dashboard.component.ts">
</code-pane> </code-pane>
<code-pane <code-pane
title="src/app/dashboard/dashboard.component.css" path="toh-pt5/src/app/dashboard/dashboard.component.css"> header="src/app/dashboard/dashboard.component.css" path="toh-pt5/src/app/dashboard/dashboard.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -571,16 +571,16 @@ Here are the code files discussed on this page and your app should look like thi
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/heroes/heroes.component.html" path="toh-pt5/src/app/heroes/heroes.component.html"> header="src/app/heroes/heroes.component.html" path="toh-pt5/src/app/heroes/heroes.component.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts"
path="toh-pt5/src/app/heroes/heroes.component.ts"> path="toh-pt5/src/app/heroes/heroes.component.ts">
</code-pane> </code-pane>
<code-pane <code-pane
title="src/app/heroes/heroes.component.css" header="src/app/heroes/heroes.component.css"
path="toh-pt5/src/app/heroes/heroes.component.css"> path="toh-pt5/src/app/heroes/heroes.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -590,15 +590,15 @@ Here are the code files discussed on this page and your app should look like thi
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/hero-detail/hero-detail.component.html" path="toh-pt5/src/app/hero-detail/hero-detail.component.html"> header="src/app/hero-detail/hero-detail.component.html" path="toh-pt5/src/app/hero-detail/hero-detail.component.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="src/app/hero-detail/hero-detail.component.ts" path="toh-pt5/src/app/hero-detail/hero-detail.component.ts"> header="src/app/hero-detail/hero-detail.component.ts" path="toh-pt5/src/app/hero-detail/hero-detail.component.ts">
</code-pane> </code-pane>
<code-pane <code-pane
title="src/app/hero-detail/hero-detail.component.css" path="toh-pt5/src/app/hero-detail/hero-detail.component.css"> header="src/app/hero-detail/hero-detail.component.css" path="toh-pt5/src/app/hero-detail/hero-detail.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>

View File

@ -21,7 +21,7 @@ To make `HttpClient` available everywhere in the app:
<code-example <code-example
path="toh-pt6/src/app/app.module.ts" path="toh-pt6/src/app/app.module.ts"
region="import-http-client" region="import-http-client"
title="src/app/app.module.ts (Http Client import)"> header="src/app/app.module.ts (Http Client import)">
</code-example> </code-example>
* add it to the `@NgModule.imports` array * add it to the `@NgModule.imports` array
@ -62,7 +62,7 @@ which you will create in a moment.
<code-example <code-example
path="toh-pt6/src/app/app.module.ts" path="toh-pt6/src/app/app.module.ts"
region="import-in-mem-stuff" region="import-in-mem-stuff"
title="src/app/app.module.ts (In-memory Web API imports)"> header="src/app/app.module.ts (In-memory Web API imports)">
</code-example> </code-example>
Add the `HttpClientInMemoryWebApiModule` to the `@NgModule.imports` array&mdash; Add the `HttpClientInMemoryWebApiModule` to the `@NgModule.imports` array&mdash;
@ -80,7 +80,7 @@ that primes the in-memory database.
The _Tour of Heroes_ sample creates such a class The _Tour of Heroes_ sample creates such a class
`src/app/in-memory-data.service.ts` which has the following content: `src/app/in-memory-data.service.ts` which has the following content:
<code-example path="toh-pt6/src/app/in-memory-data.service.ts" region="init" title="src/app/in-memory-data.service.ts" linenums="false"></code-example> <code-example path="toh-pt6/src/app/in-memory-data.service.ts" region="init" header="src/app/in-memory-data.service.ts" linenums="false"></code-example>
This file replaces `mock-heroes.ts`, which is now safe to delete. This file replaces `mock-heroes.ts`, which is now safe to delete.
@ -96,7 +96,7 @@ Import some HTTP symbols that you'll need:
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="import-httpclient" region="import-httpclient"
title="src/app/hero.service.ts (import HTTP symbols)"> header="src/app/hero.service.ts (import HTTP symbols)">
</code-example> </code-example>
Inject `HttpClient` into the constructor in a private property called `http`. Inject `HttpClient` into the constructor in a private property called `http`.
@ -132,7 +132,7 @@ as an `Observable<Hero[]>`.
<code-example <code-example
path="toh-pt4/src/app/hero.service.ts" path="toh-pt4/src/app/hero.service.ts"
region="getHeroes-1" region="getHeroes-1"
title="src/app/hero.service.ts (getHeroes with RxJs 'of()')"> header="src/app/hero.service.ts (getHeroes with RxJs 'of()')">
</code-example> </code-example>
Convert that method to use `HttpClient` Convert that method to use `HttpClient`
@ -251,7 +251,7 @@ the number of the hero that you want to retrieve. For example, `api/heroes/11`.
Add a `HeroService.getHero()` method to make that request: Add a `HeroService.getHero()` method to make that request:
<code-example path="toh-pt6/src/app/hero.service.ts" region="getHero" title="src/app/hero.service.ts"></code-example> <code-example path="toh-pt6/src/app/hero.service.ts" region="getHero" header="src/app/hero.service.ts"></code-example>
There are three significant differences from `getHeroes()`. There are three significant differences from `getHeroes()`.
@ -272,12 +272,12 @@ the server.
At the end of the hero detail template, add a save button with a `click` event At the end of the hero detail template, add a save button with a `click` event
binding that invokes a new component method named `save()`. binding that invokes a new component method named `save()`.
<code-example path="toh-pt6/src/app/hero-detail/hero-detail.component.html" region="save" title="src/app/hero-detail/hero-detail.component.html (save)"></code-example> <code-example path="toh-pt6/src/app/hero-detail/hero-detail.component.html" region="save" header="src/app/hero-detail/hero-detail.component.html (save)"></code-example>
Add the following `save()` method, which persists hero name changes using the hero service Add the following `save()` method, which persists hero name changes using the hero service
`updateHero()` method and then navigates back to the previous view. `updateHero()` method and then navigates back to the previous view.
<code-example path="toh-pt6/src/app/hero-detail/hero-detail.component.ts" region="save" title="src/app/hero-detail/hero-detail.component.ts (save)"></code-example> <code-example path="toh-pt6/src/app/hero-detail/hero-detail.component.ts" region="save" header="src/app/hero-detail/hero-detail.component.ts (save)"></code-example>
#### Add _HeroService.updateHero()_ #### Add _HeroService.updateHero()_
@ -288,7 +288,7 @@ on the server.
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="updateHero" region="updateHero"
title="src/app/hero.service.ts (update)"> header="src/app/hero.service.ts (update)">
</code-example> </code-example>
The `HttpClient.put()` method takes three parameters The `HttpClient.put()` method takes three parameters
@ -304,7 +304,7 @@ That header is in the `httpOptions` constant defined in the `HeroService`.
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="http-options" region="http-options"
title="src/app/hero.service.ts"> header="src/app/hero.service.ts">
</code-example> </code-example>
Refresh the browser, change a hero name and save your change. Navigating to the previous view is implemented in the `save()` method defined in `HeroDetailComponent`. Refresh the browser, change a hero name and save your change. Navigating to the previous view is implemented in the `save()` method defined in `HeroDetailComponent`.
@ -318,12 +318,12 @@ element paired with an add button.
Insert the following into the `HeroesComponent` template, just after Insert the following into the `HeroesComponent` template, just after
the heading: the heading:
<code-example path="toh-pt6/src/app/heroes/heroes.component.html" region="add" title="src/app/heroes/heroes.component.html (add)"></code-example> <code-example path="toh-pt6/src/app/heroes/heroes.component.html" region="add" header="src/app/heroes/heroes.component.html (add)"></code-example>
In response to a click event, call the component's click handler and then In response to a click event, call the component's click handler and then
clear the input field so that it's ready for another name. clear the input field so that it's ready for another name.
<code-example path="toh-pt6/src/app/heroes/heroes.component.ts" region="add" title="src/app/heroes/heroes.component.ts (add)"></code-example> <code-example path="toh-pt6/src/app/heroes/heroes.component.ts" region="add" header="src/app/heroes/heroes.component.ts (add)"></code-example>
When the given name is non-blank, the handler creates a `Hero`-like object When the given name is non-blank, the handler creates a `Hero`-like object
from the name (it's only missing the `id`) and passes it to the services `addHero()` method. from the name (it's only missing the `id`) and passes it to the services `addHero()` method.
@ -337,7 +337,7 @@ You'll write `HeroService.addHero` in the next section.
Add the following `addHero()` method to the `HeroService` class. Add the following `addHero()` method to the `HeroService` class.
<code-example path="toh-pt6/src/app/hero.service.ts" region="addHero" title="src/app/hero.service.ts (addHero)"></code-example> <code-example path="toh-pt6/src/app/hero.service.ts" region="addHero" header="src/app/hero.service.ts (addHero)"></code-example>
`HeroService.addHero()` differs from `updateHero` in two ways. `HeroService.addHero()` differs from `updateHero` in two ways.
@ -358,7 +358,7 @@ name in the repeated `<li>` element.
The HTML for the list of heroes should look like this: The HTML for the list of heroes should look like this:
<code-example path="toh-pt6/src/app/heroes/heroes.component.html" region="list" title="src/app/heroes/heroes.component.html (list of heroes)"></code-example> <code-example path="toh-pt6/src/app/heroes/heroes.component.html" region="list" header="src/app/heroes/heroes.component.html (list of heroes)"></code-example>
To position the delete button at the far right of the hero entry, To position the delete button at the far right of the hero entry,
add some CSS to the `heroes.component.css`. You'll find that CSS add some CSS to the `heroes.component.css`. You'll find that CSS
@ -366,7 +366,7 @@ in the [final review code](#heroescomponent) below.
Add the `delete()` handler to the component. Add the `delete()` handler to the component.
<code-example path="toh-pt6/src/app/heroes/heroes.component.ts" region="delete" title="src/app/heroes/heroes.component.ts (delete)"></code-example> <code-example path="toh-pt6/src/app/heroes/heroes.component.ts" region="delete" header="src/app/heroes/heroes.component.ts (delete)"></code-example>
Although the component delegates hero deletion to the `HeroService`, Although the component delegates hero deletion to the `HeroService`,
it remains responsible for updating its own list of heroes. it remains responsible for updating its own list of heroes.
@ -391,7 +391,7 @@ There's really nothing for the component to do with the `Observable` returned by
Add a `deleteHero()` method to `HeroService` like this. Add a `deleteHero()` method to `HeroService` like this.
<code-example path="toh-pt6/src/app/hero.service.ts" region="deleteHero" title="src/app/hero.service.ts (delete)"></code-example> <code-example path="toh-pt6/src/app/hero.service.ts" region="deleteHero" header="src/app/hero.service.ts (delete)"></code-example>
Note that Note that
@ -420,7 +420,7 @@ Start by adding a `searchHeroes` method to the `HeroService`.
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="searchHeroes" region="searchHeroes"
title="src/app/hero.service.ts"> header="src/app/hero.service.ts">
</code-example> </code-example>
The method returns immediately with an empty array if there is no search term. The method returns immediately with an empty array if there is no search term.
@ -434,7 +434,7 @@ Open the `DashboardComponent` _template_ and
Add the hero search element, `<app-hero-search>`, to the bottom of the `DashboardComponent` template. Add the hero search element, `<app-hero-search>`, to the bottom of the `DashboardComponent` template.
<code-example <code-example
path="toh-pt6/src/app/dashboard/dashboard.component.html" title="src/app/dashboard/dashboard.component.html" linenums="false"> path="toh-pt6/src/app/dashboard/dashboard.component.html" header="src/app/dashboard/dashboard.component.html" linenums="false">
</code-example> </code-example>
This template looks a lot like the `*ngFor` repeater in the `HeroesComponent` template. This template looks a lot like the `*ngFor` repeater in the `HeroesComponent` template.
@ -456,7 +456,7 @@ The CLI generates the three `HeroSearchComponent` files and adds the component t
Replace the generated `HeroSearchComponent` _template_ with a text box and a list of matching search results like this. Replace the generated `HeroSearchComponent` _template_ with a text box and a list of matching search results like this.
<code-example path="toh-pt6/src/app/hero-search/hero-search.component.html" title="src/app/hero-search/hero-search.component.html"></code-example> <code-example path="toh-pt6/src/app/hero-search/hero-search.component.html" header="src/app/hero-search/hero-search.component.html"></code-example>
Add private CSS styles to `hero-search.component.css` Add private CSS styles to `hero-search.component.css`
as listed in the [final code review](#herosearchcomponent) below. as listed in the [final code review](#herosearchcomponent) below.
@ -487,7 +487,7 @@ do so in the component class.
Replace the generated `HeroSearchComponent` class and metadata as follows. Replace the generated `HeroSearchComponent` class and metadata as follows.
<code-example path="toh-pt6/src/app/hero-search/hero-search.component.ts" title="src/app/hero-search/hero-search.component.ts"></code-example> <code-example path="toh-pt6/src/app/hero-search/hero-search.component.ts" header="src/app/hero-search/hero-search.component.ts"></code-example>
Notice the declaration of `heroes$` as an `Observable` Notice the declaration of `heroes$` as an `Observable`
<code-example <code-example
@ -589,15 +589,15 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
<code-tabs> <code-tabs>
<code-pane <code-pane
title="hero.service.ts" header="hero.service.ts"
path="toh-pt6/src/app/hero.service.ts"> path="toh-pt6/src/app/hero.service.ts">
</code-pane> </code-pane>
<code-pane <code-pane
title="in-memory-data.service.ts" header="in-memory-data.service.ts"
path="toh-pt6/src/app/in-memory-data.service.ts"> path="toh-pt6/src/app/in-memory-data.service.ts">
</code-pane> </code-pane>
<code-pane <code-pane
title="app.module.ts" header="app.module.ts"
path="toh-pt6/src/app/app.module.ts"> path="toh-pt6/src/app/app.module.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -607,15 +607,15 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
<code-tabs> <code-tabs>
<code-pane <code-pane
title="heroes/heroes.component.html" header="heroes/heroes.component.html"
path="toh-pt6/src/app/heroes/heroes.component.html"> path="toh-pt6/src/app/heroes/heroes.component.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="heroes/heroes.component.ts" header="heroes/heroes.component.ts"
path="toh-pt6/src/app/heroes/heroes.component.ts"> path="toh-pt6/src/app/heroes/heroes.component.ts">
</code-pane> </code-pane>
<code-pane <code-pane
title="heroes/heroes.component.css" header="heroes/heroes.component.css"
path="toh-pt6/src/app/heroes/heroes.component.css"> path="toh-pt6/src/app/heroes/heroes.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -625,11 +625,11 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
<code-tabs> <code-tabs>
<code-pane <code-pane
title="hero-detail/hero-detail.component.html" header="hero-detail/hero-detail.component.html"
path="toh-pt6/src/app/hero-detail/hero-detail.component.html"> path="toh-pt6/src/app/hero-detail/hero-detail.component.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="hero-detail/hero-detail.component.ts" header="hero-detail/hero-detail.component.ts"
path="toh-pt6/src/app/hero-detail/hero-detail.component.ts"> path="toh-pt6/src/app/hero-detail/hero-detail.component.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -639,7 +639,7 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/dashboard/dashboard.component.html" header="src/app/dashboard/dashboard.component.html"
path="toh-pt6/src/app/dashboard/dashboard.component.html"> path="toh-pt6/src/app/dashboard/dashboard.component.html">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -649,15 +649,15 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
<code-tabs> <code-tabs>
<code-pane <code-pane
title="hero-search/hero-search.component.html" header="hero-search/hero-search.component.html"
path="toh-pt6/src/app/hero-search/hero-search.component.html"> path="toh-pt6/src/app/hero-search/hero-search.component.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="hero-search/hero-search.component.ts" header="hero-search/hero-search.component.ts"
path="toh-pt6/src/app/hero-search/hero-search.component.ts"> path="toh-pt6/src/app/hero-search/hero-search.component.ts">
</code-pane> </code-pane>
<code-pane <code-pane
title="hero-search/hero-search.component.css" header="hero-search/hero-search.component.css"
path="toh-pt6/src/app/hero-search/hero-search.component.css"> path="toh-pt6/src/app/hero-search/hero-search.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>

View File

@ -33,18 +33,18 @@ describe('CodeExampleComponent', () => {
expect(codeExampleComponent.aioCode.code.trim()).toBe(`const foo = "bar";`); expect(codeExampleComponent.aioCode.code.trim()).toBe(`const foo = "bar";`);
}); });
it('should change aio-code classes based on title presence', () => { it('should change aio-code classes based on header presence', () => {
expect(codeExampleComponent.title).toBe('Great Example'); expect(codeExampleComponent.header).toBe('Great Example');
expect(fixture.nativeElement.querySelector('header')).toBeTruthy(); expect(fixture.nativeElement.querySelector('header')).toBeTruthy();
expect(codeExampleComponent.classes).toEqual({ expect(codeExampleComponent.classes).toEqual({
'headed-code': true, 'headed-code': true,
'simple-code': false 'simple-code': false
}); });
codeExampleComponent.title = ''; codeExampleComponent.header = '';
fixture.detectChanges(); fixture.detectChanges();
expect(codeExampleComponent.title).toBe(''); expect(codeExampleComponent.header).toBe('');
expect(fixture.nativeElement.querySelector('header')).toBeFalsy(); expect(fixture.nativeElement.querySelector('header')).toBeFalsy();
expect(codeExampleComponent.classes).toEqual({ expect(codeExampleComponent.classes).toEqual({
'headed-code': false, 'headed-code': false,
@ -85,14 +85,14 @@ describe('CodeExampleComponent', () => {
@Component({ @Component({
selector: 'aio-host-comp', selector: 'aio-host-comp',
template: ` template: `
<code-example [title]="title" [path]="path" [hidecopy]="hidecopy"> <code-example [header]="header" [path]="path" [hidecopy]="hidecopy">
{{code}} {{code}}
</code-example> </code-example>
` `
}) })
class HostComponent { class HostComponent {
code = `const foo = "bar";`; code = `const foo = "bar";`;
title = 'Great Example'; header = 'Great Example';
path = 'code-path'; path = 'code-path';
hidecopy: boolean | string = false; hidecopy: boolean | string = false;

View File

@ -7,7 +7,7 @@ import { CodeComponent } from './code.component';
* Example usage: * Example usage:
* *
* ``` * ```
* <code-example language="ts" linenums="2" class="special" title="Do Stuff"> * <code-example language="ts" linenums="2" class="special" header="Do Stuff">
* // a code block * // a code block
* console.log('do stuff'); * console.log('do stuff');
* </code-example> * </code-example>
@ -19,7 +19,7 @@ import { CodeComponent } from './code.component';
<!-- Content projection is used to get the content HTML provided to this component --> <!-- Content projection is used to get the content HTML provided to this component -->
<div #content style="display: none"><ng-content></ng-content></div> <div #content style="display: none"><ng-content></ng-content></div>
<header *ngIf="title">{{title}}</header> <header *ngIf="header">{{header}}</header>
<aio-code [ngClass]="classes" <aio-code [ngClass]="classes"
[language]="language" [language]="language"
@ -27,7 +27,7 @@ import { CodeComponent } from './code.component';
[path]="path" [path]="path"
[region]="region" [region]="region"
[hideCopy]="hidecopy" [hideCopy]="hidecopy"
[title]="title"> [header]="header">
</aio-code> </aio-code>
`, `,
}) })
@ -41,15 +41,15 @@ export class CodeExampleComponent implements AfterViewInit {
@Input() region: string; @Input() region: string;
@Input() @Input()
set title(title: string) { set header(header: string) {
this._title = title; this._header = header;
this.classes = { this.classes = {
'headed-code': !!this.title, 'headed-code': !!this.header,
'simple-code': !this.title, 'simple-code': !this.header,
}; };
} }
get title(): string { return this._title; } get header(): string { return this._header; }
private _title: string; private _header: string;
@Input() @Input()
set path(path: string) { set path(path: string) {

View File

@ -39,7 +39,7 @@ describe('CodeTabsComponent', () => {
expect(tabs[0].linenums).toBe('linenums-A'); expect(tabs[0].linenums).toBe('linenums-A');
expect(tabs[0].path).toBe('path-A'); expect(tabs[0].path).toBe('path-A');
expect(tabs[0].region).toBe('region-A'); expect(tabs[0].region).toBe('region-A');
expect(tabs[0].title).toBe('title-A'); expect(tabs[0].header).toBe('header-A');
expect(tabs[0].code.trim()).toBe('Code example 1'); expect(tabs[0].code.trim()).toBe('Code example 1');
// Second code pane expectations // Second code pane expectations
@ -48,7 +48,7 @@ describe('CodeTabsComponent', () => {
expect(tabs[1].linenums).toBe('default-linenums', 'Default linenums should have been used'); expect(tabs[1].linenums).toBe('default-linenums', 'Default linenums should have been used');
expect(tabs[1].path).toBe('path-B'); expect(tabs[1].path).toBe('path-B');
expect(tabs[1].region).toBe('region-B'); expect(tabs[1].region).toBe('region-B');
expect(tabs[1].title).toBe('title-B'); expect(tabs[1].header).toBe('header-B');
expect(tabs[1].code.trim()).toBe('Code example 2'); expect(tabs[1].code.trim()).toBe('Code example 2');
}); });
@ -56,10 +56,10 @@ describe('CodeTabsComponent', () => {
const matTabs = fixture.nativeElement.querySelectorAll('.mat-tab-label'); const matTabs = fixture.nativeElement.querySelectorAll('.mat-tab-label');
expect(matTabs.length).toBe(2); expect(matTabs.length).toBe(2);
expect(matTabs[0].textContent.trim()).toBe('title-A'); expect(matTabs[0].textContent.trim()).toBe('header-A');
expect(matTabs[0].querySelector('.class-A')).toBeTruthy(); expect(matTabs[0].querySelector('.class-A')).toBeTruthy();
expect(matTabs[1].textContent.trim()).toBe('title-B'); expect(matTabs[1].textContent.trim()).toBe('header-B');
expect(matTabs[1].querySelector('.class-B')).toBeTruthy(); expect(matTabs[1].querySelector('.class-B')).toBeTruthy();
}); });
@ -78,14 +78,14 @@ describe('CodeTabsComponent', () => {
linenums="linenums-A" linenums="linenums-A"
path="path-A" path="path-A"
region="region-A" region="region-A"
title="title-A"> header="header-A">
Code example 1 Code example 1
</code-pane> </code-pane>
<code-pane class="class-B" <code-pane class="class-B"
language="language-B" language="language-B"
path="path-B" path="path-B"
region="region-B" region="region-B"
title="title-B"> header="header-B">
Code example 2 Code example 2
</code-pane> </code-pane>
</code-tabs> </code-tabs>

View File

@ -9,7 +9,7 @@ export interface TabInfo {
linenums: any; linenums: any;
path: string; path: string;
region: string; region: string;
title: string|null; header: string|null;
} }
/** /**
@ -29,14 +29,14 @@ export interface TabInfo {
<mat-tab-group class="code-tab-group" disableRipple> <mat-tab-group class="code-tab-group" disableRipple>
<mat-tab style="overflow-y: hidden;" *ngFor="let tab of tabs"> <mat-tab style="overflow-y: hidden;" *ngFor="let tab of tabs">
<ng-template mat-tab-label> <ng-template mat-tab-label>
<span class="{{ tab.class }}">{{ tab.title }}</span> <span class="{{ tab.class }}">{{ tab.header }}</span>
</ng-template> </ng-template>
<aio-code class="{{ tab.class }}" <aio-code class="{{ tab.class }}"
[language]="tab.language" [language]="tab.language"
[linenums]="tab.linenums" [linenums]="tab.linenums"
[path]="tab.path" [path]="tab.path"
[region]="tab.region" [region]="tab.region"
[title]="tab.title"> [header]="tab.header">
</aio-code> </aio-code>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
@ -77,7 +77,7 @@ export class CodeTabsComponent implements OnInit, AfterViewInit {
linenums: tabContent.getAttribute('linenums') || this.linenums, linenums: tabContent.getAttribute('linenums') || this.linenums,
path: tabContent.getAttribute('path') || '', path: tabContent.getAttribute('path') || '',
region: tabContent.getAttribute('region') || '', region: tabContent.getAttribute('region') || '',
title: tabContent.getAttribute('title') header: tabContent.getAttribute('header')
}; };
} }
} }

View File

@ -200,10 +200,10 @@ describe('CodeComponent', () => {
expect(getButton().getAttribute('aria-label')).toBe(''); expect(getButton().getAttribute('aria-label')).toBe('');
}); });
it('should have aria-label explaining what is being copied when title passed in', () => { it('should have aria-label explaining what is being copied when header passed in', () => {
hostComponent.title = 'a/b/c/foo.ts'; hostComponent.header = 'a/b/c/foo.ts';
fixture.detectChanges(); fixture.detectChanges();
expect(getButton().getAttribute('aria-label')).toContain(hostComponent.title); expect(getButton().getAttribute('aria-label')).toContain(hostComponent.header);
}); });
it('should call copier service when clicked', () => { it('should call copier service when clicked', () => {
@ -273,7 +273,7 @@ describe('CodeComponent', () => {
template: ` template: `
<aio-code [language]="language" <aio-code [language]="language"
[linenums]="linenums" [path]="path" [region]="region" [linenums]="linenums" [path]="path" [region]="region"
[hideCopy]="hideCopy" [title]="title"></aio-code> [hideCopy]="hideCopy" [header]="header"></aio-code>
` `
}) })
class HostComponent implements AfterViewInit { class HostComponent implements AfterViewInit {
@ -282,7 +282,7 @@ class HostComponent implements AfterViewInit {
linenums: boolean | number | string; linenums: boolean | number | string;
path: string; path: string;
region: string; region: string;
title: string; header: string;
@ViewChild(CodeComponent) codeComponent: CodeComponent; @ViewChild(CodeComponent) codeComponent: CodeComponent;

View File

@ -85,14 +85,14 @@ export class CodeComponent implements OnChanges {
/** Region of the source of the code being displayed. */ /** Region of the source of the code being displayed. */
@Input() region: string; @Input() region: string;
/** Optional title to be displayed above the code. */ /** Optional header to be displayed above the code. */
@Input() @Input()
set title(title: string) { set header(header: string) {
this._title = title; this._header = header;
this.ariaLabel = this.title ? `Copy code snippet from ${this.title}` : ''; this.ariaLabel = this.header ? `Copy code snippet from ${this.header}` : '';
} }
get title(): string { return this._title; } get header(): string { return this._header; }
private _title: string; private _header: string;
@Output() codeFormatted = new EventEmitter<void>(); @Output() codeFormatted = new EventEmitter<void>();

View File

@ -3,19 +3,19 @@ var entities = require('entities');
/** /**
* @dgService exampleInlineTagDef * @dgService exampleInlineTagDef
* @description * @description
* Process inline example tags (of the form {@example relativePath region -title='some title' * Process inline example tags (of the form {@example relativePath region -header='some header'
* -stylePattern='{some style pattern}' }), * -stylePattern='{some style pattern}' }),
* replacing them with code from a shredded file * replacing them with code from a shredded file
* Examples: * Examples:
* {@example core/application_spec.ts hello-app -title='Sample component' } * {@example core/application_spec.ts hello-app -header='Sample component' }
* {@example core/application_spec.ts -region=hello-app -title='Sample component' } * {@example core/application_spec.ts -region=hello-app -header='Sample component' }
* @kind function * @kind function
*/ */
module.exports = function exampleInlineTagDef(parseArgString, createDocMessage, getExampleRegion) { module.exports = function exampleInlineTagDef(parseArgString, createDocMessage, getExampleRegion) {
return { return {
name: 'example', name: 'example',
description: description:
'Process inline example tags (of the form {@example some/uri Some Title}), replacing them with HTML anchors', 'Process inline example tags (of the form {@example some/uri some-region Some header}), replacing them with HTML anchors',
handler: function(doc, tagName, tagDescription) { handler: function(doc, tagName, tagDescription) {
@ -24,14 +24,14 @@ module.exports = function exampleInlineTagDef(parseArgString, createDocMessage,
var relativePath = unnamedArgs[0]; var relativePath = unnamedArgs[0];
var regionName = tagArgs.region || (unnamedArgs.length > 1 ? unnamedArgs[1] : ''); var regionName = tagArgs.region || (unnamedArgs.length > 1 ? unnamedArgs[1] : '');
if (regionName === '\'\'') regionName = ''; if (regionName === '\'\'') regionName = '';
var title = tagArgs.title || (unnamedArgs.length > 2 ? unnamedArgs.slice(2).join(' ') : null); var header = tagArgs.header || (unnamedArgs.length > 2 ? unnamedArgs.slice(2).join(' ') : null);
var linenums = tagArgs.linenums; var linenums = tagArgs.linenums;
// var stylePattern = tagArgs.stylePattern; // TODO: not yet implemented here // var stylePattern = tagArgs.stylePattern; // TODO: not yet implemented here
const sourceCode = getExampleRegion(doc, relativePath, regionName); const sourceCode = getExampleRegion(doc, relativePath, regionName);
const attributes = []; const attributes = [];
if (title) attributes.push(` title="${title}"`); if (header) attributes.push(` header="${header}"`);
if (linenums !== undefined) attributes.push(` linenums="${linenums}"`); if (linenums !== undefined) attributes.push(` linenums="${linenums}"`);
return '<code-example' + attributes.join('') + '>\n' + sourceCode + '\n</code-example>'; return '<code-example' + attributes.join('') + '>\n' + sourceCode + '\n</code-example>';

View File

@ -49,14 +49,14 @@ describe('example inline-tag-def', function() {
expect(handler({}, 'example', 'test/url region-1')).toEqual('<code-example>\nregion 1 contents\n</code-example>'); expect(handler({}, 'example', 'test/url region-1')).toEqual('<code-example>\nregion 1 contents\n</code-example>');
}); });
it('should add a title if specified', () => { it('should add a header if specified', () => {
expect(handler({}, 'example', 'test/url region-1 \'Some Title\'')).toEqual('<code-example title="Some Title">\nregion 1 contents\n</code-example>'); expect(handler({}, 'example', 'test/url region-1 \'Some Header\'')).toEqual('<code-example header="Some Header">\nregion 1 contents\n</code-example>');
expect(handler({}, 'example', 'test/url region-1 Some Title')).toEqual('<code-example title="Some Title">\nregion 1 contents\n</code-example>'); expect(handler({}, 'example', 'test/url region-1 Some Header')).toEqual('<code-example header="Some Header">\nregion 1 contents\n</code-example>');
}); });
it('should contain the whole contents from the example file if an empty ("") region is specified', () => { it('should contain the whole contents from the example file if an empty ("") region is specified', () => {
expect(handler({}, 'example', 'test/url \'\'')).toEqual('<code-example>\nwhole file\n</code-example>'); expect(handler({}, 'example', 'test/url \'\'')).toEqual('<code-example>\nwhole file\n</code-example>');
expect(handler({}, 'example', 'test/url \'\' Some Title')).toEqual('<code-example title="Some Title">\nwhole file\n</code-example>'); expect(handler({}, 'example', 'test/url \'\' Some Header')).toEqual('<code-example header="Some Header">\nwhole file\n</code-example>');
}); });
it('should add in linenum attribute if specified', () => { it('should add in linenum attribute if specified', () => {