refactor(docs-infra): remove linenums=false since it is now the default (#31674)
PR Close #31674
This commit is contained in:
committed by
Miško Hevery
parent
dd0be7feb7
commit
1bcd58cee8
@@ -66,7 +66,7 @@ The following table lists some of the key AngularJS template features with their
|
||||
|
||||
### Bindings/interpolation
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="interpolation" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="interpolation"></code-example>
|
||||
|
||||
|
||||
In Angular, a template expression in curly braces still denotes one-way binding.
|
||||
@@ -102,7 +102,7 @@ The following table lists some of the key AngularJS template features with their
|
||||
|
||||
### Pipes
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="uppercase" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="uppercase"></code-example>
|
||||
|
||||
|
||||
In Angular you use similar syntax with the pipe (|) character to filter output, but now you call them **pipes**.
|
||||
@@ -136,7 +136,7 @@ The following table lists some of the key AngularJS template features with their
|
||||
|
||||
### Input variables
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="local" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="local"></code-example>
|
||||
|
||||
|
||||
Angular has true template input variables that are explicitly defined using the `let` keyword.
|
||||
@@ -202,10 +202,10 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### Bootstrapping
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/main.ts" header="main.ts" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/main.ts" header="main.ts"></code-example>
|
||||
<br>
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" header="app.module.ts" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" header="app.module.ts"></code-example>
|
||||
|
||||
|
||||
Angular doesn't have a bootstrap directive.
|
||||
@@ -245,7 +245,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### ngClass
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="ngClass" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="ngClass"></code-example>
|
||||
|
||||
|
||||
In Angular, the `ngClass` directive works similarly.
|
||||
@@ -291,7 +291,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### Bind to the `click` event
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="event-binding" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="event-binding"></code-example>
|
||||
|
||||
|
||||
AngularJS event-based directives do not exist in Angular.
|
||||
@@ -338,7 +338,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### Component decorator
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="component" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="component"></code-example>
|
||||
|
||||
|
||||
In Angular, the template no longer specifies its associated controller.
|
||||
@@ -401,7 +401,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### Bind to the `href` property
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="href" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="href"></code-example>
|
||||
|
||||
|
||||
Angular uses property binding; there is no built-in *href* directive.
|
||||
@@ -412,7 +412,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
In Angular, `href` is no longer used for routing. Routing uses `routerLink`, as shown in the following example.
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="router-link" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="router-link"></code-example>
|
||||
|
||||
|
||||
For more information on routing, see the [RouterLink binding](guide/router#router-link)
|
||||
@@ -445,7 +445,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### *ngIf
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngIf" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngIf"></code-example>
|
||||
|
||||
|
||||
The `*ngIf` directive in Angular works the same as the `ng-if` directive in AngularJS. It removes
|
||||
@@ -480,7 +480,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### ngModel
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngModel" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngModel"></code-example>
|
||||
|
||||
|
||||
In Angular, **two-way binding** is denoted by `[()]`, descriptively referred to as a "banana in a box". This syntax is a shortcut for defining both property binding (from the component to the view)
|
||||
@@ -516,7 +516,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### *ngFor
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngFor" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngFor"></code-example>
|
||||
|
||||
|
||||
The `*ngFor` directive in Angular is similar to the `ng-repeat` directive in AngularJS. It repeats
|
||||
@@ -559,7 +559,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### Bind to the `hidden` property
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="hidden" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="hidden"></code-example>
|
||||
|
||||
|
||||
Angular uses property binding; there is no built-in *show* directive.
|
||||
@@ -598,7 +598,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### Bind to the `src` property
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="src" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="src"></code-example>
|
||||
|
||||
|
||||
Angular uses property binding; there is no built-in *src* directive.
|
||||
@@ -635,7 +635,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### ngStyle
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="ngStyle" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="ngStyle"></code-example>
|
||||
|
||||
|
||||
In Angular, the `ngStyle` directive works similarly. It sets a CSS style on an HTML element based on an expression.
|
||||
@@ -690,7 +690,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### ngSwitch
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngSwitch" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngSwitch"></code-example>
|
||||
|
||||
|
||||
In Angular, the `ngSwitch` directive works similarly.
|
||||
@@ -765,7 +765,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
### currency
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="currency" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="currency"></code-example>
|
||||
|
||||
|
||||
The Angular `currency` pipe is similar although some of the parameters have changed.
|
||||
@@ -793,7 +793,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
### date
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="date" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="date"></code-example>
|
||||
|
||||
|
||||
The Angular `date` pipe is similar.
|
||||
@@ -847,7 +847,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
### json
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="json" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="json"></code-example>
|
||||
|
||||
|
||||
The Angular `json` pipe does the same thing.
|
||||
@@ -876,7 +876,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
### slice
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="slice" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="slice"></code-example>
|
||||
|
||||
|
||||
The `SlicePipe` does the same thing but the *order of the parameters is reversed*, in keeping
|
||||
@@ -907,7 +907,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
### lowercase
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="lowercase" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="lowercase"></code-example>
|
||||
|
||||
|
||||
The Angular `lowercase` pipe does the same thing.
|
||||
@@ -935,7 +935,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
### number
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="number" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="number"></code-example>
|
||||
|
||||
|
||||
The Angular `number` pipe is similar.
|
||||
@@ -1068,7 +1068,7 @@ The Angular code is shown using TypeScript.
|
||||
|
||||
### NgModules
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts"></code-example>
|
||||
|
||||
|
||||
NgModules, defined with the `NgModule` decorator, serve the same purpose:
|
||||
@@ -1109,7 +1109,7 @@ The Angular code is shown using TypeScript.
|
||||
|
||||
### Component decorator
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="component" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="component"></code-example>
|
||||
|
||||
|
||||
Angular adds a decorator to the component class to provide any required metadata.
|
||||
@@ -1145,7 +1145,7 @@ The Angular code is shown using TypeScript.
|
||||
|
||||
### Component class
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="class" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="class"></code-example>
|
||||
|
||||
|
||||
In Angular, you create a component class.
|
||||
@@ -1184,7 +1184,7 @@ The Angular code is shown using TypeScript.
|
||||
|
||||
### Dependency injection
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="di" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="di"></code-example>
|
||||
|
||||
|
||||
In Angular, you pass in dependencies as arguments to the component class constructor.
|
||||
@@ -1254,7 +1254,7 @@ also encapsulate a style sheet within a specific component.
|
||||
|
||||
|
||||
### Styles configuration
|
||||
<code-example hideCopy path="ajs-quick-reference/.angular-cli.1.json" region="styles" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/.angular-cli.1.json" region="styles"></code-example>
|
||||
|
||||
With the Angular CLI, you can configure your global styles in the `angular.json` file.
|
||||
You can rename the extension to `.scss` to use sass.
|
||||
@@ -1263,7 +1263,7 @@ also encapsulate a style sheet within a specific component.
|
||||
In Angular, you can use the `styles` or `styleUrls` property of the `@Component` metadata to define
|
||||
a style sheet for a particular component.
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="style-url" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="style-url"></code-example>
|
||||
|
||||
|
||||
This allows you to set appropriate styles for individual components that won’t leak into
|
||||
|
||||
@@ -37,8 +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.
|
||||
|
||||
<code-example path="animations/src/app/app.module.1.ts" header="src/app/app.module.ts" language="typescript" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="animations/src/app/app.module.1.ts" header="src/app/app.module.ts" language="typescript"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@@ -180,9 +179,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.
|
||||
|
||||
<code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript"
|
||||
region="component" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript" region="component"></code-example>
|
||||
|
||||
When you've defined an animation trigger for a component, you can attach it to an element in that component's template by wrapping the trigger name in brackets and preceding it with an `@` symbol. Then, you can bind the trigger to a template expression using standard Angular property binding syntax as shown below, where `triggerName` is the name of the trigger, and `expression` evaluates to a defined animation state.
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Angular offers two ways to compile your application:
|
||||
1. **_Just-in-Time_ (JIT)**, which compiles your app in the browser at runtime.
|
||||
1. **_Ahead-of-Time_ (AOT)**, which compiles your app at build time.
|
||||
|
||||
JIT compilation is the default when you run the [`ng build`](cli/build) (build only) or [`ng serve`](cli/serve) (build and serve locally) CLI commands:
|
||||
JIT compilation is the default when you run the [`ng build`](cli/build) (build only) or [`ng serve`](cli/serve) (build and serve locally) CLI commands:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng build
|
||||
@@ -945,7 +945,7 @@ import { calculateValue } from './utilities';
|
||||
|
||||
To correct this error, export a function from the module and refer to the function in a `useFactory` provider instead.
|
||||
|
||||
<code-example linenums="false">
|
||||
<code-example>
|
||||
// CORRECTED
|
||||
import { calculateValue } from './utilities';
|
||||
|
||||
@@ -978,7 +978,7 @@ The compiler does not support references to variables assigned by [destructuring
|
||||
|
||||
For example, you cannot write something like this:
|
||||
|
||||
<code-example linenums="false">
|
||||
<code-example>
|
||||
// ERROR
|
||||
import { configuration } from './configuration';
|
||||
|
||||
@@ -994,7 +994,7 @@ const {foo, bar} = configuration;
|
||||
|
||||
To correct this error, refer to non-destructured values.
|
||||
|
||||
<code-example linenums="false">
|
||||
<code-example>
|
||||
// CORRECTED
|
||||
import { configuration } from './configuration';
|
||||
...
|
||||
@@ -1041,7 +1041,7 @@ you can finesse the problem in four steps:
|
||||
|
||||
Here's an illustrative example.
|
||||
|
||||
<code-example linenums="false">
|
||||
<code-example>
|
||||
// CORRECTED
|
||||
import { Inject } from '@angular/core';
|
||||
|
||||
@@ -1064,7 +1064,7 @@ uses the `@Inject(WINDOW)` to generate the injection code.
|
||||
|
||||
Angular does something similar with the `DOCUMENT` token so you can inject the browser's `document` object (or an abstraction of it, depending upon the platform in which the application runs).
|
||||
|
||||
<code-example linenums="false">
|
||||
<code-example>
|
||||
import { Inject } from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/platform-browser';
|
||||
|
||||
@@ -1101,7 +1101,7 @@ that you referenced in metadata.
|
||||
|
||||
The compiler can understand simple enum values but not complex values such as those derived from computed properties.
|
||||
|
||||
<code-example linenums="false">
|
||||
<code-example>
|
||||
// ERROR
|
||||
enum Colors {
|
||||
Red = 1,
|
||||
@@ -1311,7 +1311,7 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
|
||||
{@a tsconfig-extends}
|
||||
## Configuration inheritance with extends
|
||||
Similar to TypeScript Compiler, Angular Compiler also supports `extends` in the `tsconfig.json` on `angularCompilerOptions`. A tsconfig file can inherit configurations from another file using the `extends` property.
|
||||
The `extends` is a top level property parallel to `compilerOptions` and `angularCompilerOptions`.
|
||||
The `extends` is a top level property parallel to `compilerOptions` and `angularCompilerOptions`.
|
||||
The configuration from the base file are loaded first, then overridden by those in the inheriting config file.
|
||||
Example:
|
||||
```json
|
||||
|
||||
@@ -10,7 +10,7 @@ Learn more in [The App Shell Model](https://developers.google.com/web/fundamenta
|
||||
## Step 1: Prepare the application
|
||||
|
||||
You can do this with the following CLI command:
|
||||
<code-example format="." language="bash" linenums="false">
|
||||
<code-example format="." language="bash">
|
||||
ng new my-app --routing
|
||||
</code-example>
|
||||
|
||||
@@ -20,7 +20,7 @@ For an existing application, you have to manually add the `RouterModule` and def
|
||||
|
||||
Use the CLI to automatically create the app shell.
|
||||
|
||||
<code-example format="." language="bash" linenums="false">
|
||||
<code-example format="." language="bash">
|
||||
ng generate app-shell --client-project my-app --universal-project server-app
|
||||
</code-example>
|
||||
|
||||
@@ -29,7 +29,7 @@ ng generate app-shell --client-project my-app --universal-project server-app
|
||||
|
||||
After running this command you will notice that the `angular.json` configuration file has been updated to add two new targets, with a few other changes.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example format="." language="json">
|
||||
"server": {
|
||||
"builder": "@angular-devkit/build-angular:server",
|
||||
"options": {
|
||||
@@ -52,7 +52,7 @@ After running this command you will notice that the `angular.json` configuration
|
||||
|
||||
Use the CLI to build the `app-shell` target.
|
||||
|
||||
<code-example format="." language="bash" linenums="false">
|
||||
<code-example format="." language="bash">
|
||||
ng run my-app:app-shell
|
||||
</code-example>
|
||||
|
||||
|
||||
@@ -10,12 +10,12 @@ For example, individual components define and control each of the following view
|
||||
You define a component's application logic—what it does to support the view—inside a class.
|
||||
The class interacts with the view through an API of properties and methods.
|
||||
|
||||
For example, `HeroListComponent` has a `heroes` property that holds an array of heroes.
|
||||
Its `selectHero()` method sets a `selectedHero` property when the user clicks to choose a hero from that list.
|
||||
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.
|
||||
For example, `HeroListComponent` has a `heroes` property that holds an array of heroes.
|
||||
Its `selectHero()` method sets a `selectedHero` property when the user clicks to choose a hero from that list.
|
||||
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.
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (class)" region="class"></code-example>
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" 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()`.
|
||||
|
||||
@@ -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`.
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" header="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
|
||||
|
||||
This example shows some of the most useful `@Component` configuration options:
|
||||
|
||||
@@ -40,7 +40,7 @@ Angular inserts an instance of the `HeroListComponent` view between those tags.
|
||||
|
||||
* `templateUrl`: The module-relative address of this component's HTML template. Alternatively, you can provide the HTML template inline, as the value of the `template` property. This template defines the component's *host view*.
|
||||
|
||||
* `providers`: An array of [providers](guide/glossary#provider) for services that the component requires. In the example, this tells Angular how to provide the `HeroService` instance that the component's constructor uses to get the list of heroes to display.
|
||||
* `providers`: An array of [providers](guide/glossary#provider) for services that the component requires. In the example, this tells Angular how to provide the `HeroService` instance that the component's constructor uses to get the list of heroes to display.
|
||||
|
||||
|
||||
## Templates and views
|
||||
@@ -69,7 +69,7 @@ This template uses typical HTML elements like `<h2>` and `<p>`, and also includ
|
||||
|
||||
* The `*ngFor` directive tells Angular to iterate over a list.
|
||||
* `{{hero.name}}`, `(click)`, and `[hero]` bind program data to and from the DOM, responding to user input. See more about [data binding](#data-binding) below.
|
||||
* The `<app-hero-detail>` tag in the example is an element that represents a new component, `HeroDetailComponent`.
|
||||
* The `<app-hero-detail>` tag in the example is an element that represents a new component, `HeroDetailComponent`.
|
||||
`HeroDetailComponent` (code not shown) defines the hero-detail child view of `HeroListComponent`.
|
||||
Notice how custom components like this mix seamlessly with native HTML in the same layouts.
|
||||
|
||||
@@ -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.
|
||||
|
||||
<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>
|
||||
<code-example path="architecture/src/app/hero-list.component.1.html" header="src/app/hero-list.component.html (binding)" region="binding"></code-example>
|
||||
|
||||
* The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation)
|
||||
displays the component's `hero.name` property value within the `<li>` element.
|
||||
@@ -97,11 +97,11 @@ displays the component's `hero.name` property value within the `<li>` element.
|
||||
|
||||
* The `(click)` [*event binding*](guide/user-input#binding-to-user-input-events) calls the component's `selectHero` method when the user clicks a hero's name.
|
||||
|
||||
Two-way data binding (used mainly in [template-driven forms](guide/forms))
|
||||
combines property and event binding in a single notation.
|
||||
Two-way data binding (used mainly in [template-driven forms](guide/forms))
|
||||
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.
|
||||
|
||||
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
||||
<code-example path="architecture/src/app/hero-detail.component.html" 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.
|
||||
The user's changes also flow back to the component, resetting the property to the latest value,
|
||||
@@ -151,20 +151,20 @@ Angular templates are *dynamic*. When Angular renders them, it transforms the DO
|
||||
|
||||
A component is technically a directive.
|
||||
However, components are so distinctive and central to Angular applications that Angular
|
||||
defines the `@Component()` decorator, which extends the `@Directive()` decorator with
|
||||
defines the `@Component()` decorator, which extends the `@Directive()` decorator with
|
||||
template-oriented features.
|
||||
|
||||
In addition to components, there are two other kinds of directives: *structural* and *attribute*.
|
||||
In addition to components, there are two other kinds of directives: *structural* and *attribute*.
|
||||
Angular defines a number of directives of both kinds, and you can define your own using the `@Directive()` decorator.
|
||||
|
||||
Just as for components, the metadata for a directive associates the decorated class with a `selector` element that you use to insert it into HTML. In templates, directives typically appear within an element tag as attributes, either by name or as the target of an assignment or a binding.
|
||||
|
||||
#### Structural directives
|
||||
|
||||
*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.
|
||||
|
||||
<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>
|
||||
<code-example path="architecture/src/app/hero-list.component.1.html" 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.
|
||||
* [`*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.
|
||||
|
||||
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
||||
<code-example path="architecture/src/app/hero-detail.component.html" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
||||
|
||||
Angular has more pre-defined directives that either alter the layout structure
|
||||
(for example, [ngSwitch](guide/template-syntax#ngSwitch))
|
||||
|
||||
@@ -23,7 +23,7 @@ An NgModule is defined by a class decorated with `@NgModule()`. The `@NgModule()
|
||||
|
||||
Here's a simple root NgModule definition.
|
||||
|
||||
<code-example path="architecture/src/app/mini-app.ts" region="module" header="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"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@@ -69,9 +69,9 @@ In JavaScript each *file* is a module and all objects defined in the file belong
|
||||
The module declares some objects to be public by marking them with the `export` key word.
|
||||
Other JavaScript modules use *import statements* to access public objects from other modules.
|
||||
|
||||
<code-example path="architecture/src/app/app.module.ts" region="imports" linenums="false"></code-example>
|
||||
<code-example path="architecture/src/app/app.module.ts" region="imports"></code-example>
|
||||
|
||||
<code-example path="architecture/src/app/app.module.ts" region="export" linenums="false"></code-example>
|
||||
<code-example path="architecture/src/app/app.module.ts" region="export"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
<a href="http://exploringjs.com/es6/ch_modules.html">Learn more about the JavaScript module system on the web.</a>
|
||||
@@ -87,17 +87,17 @@ Angular loads as a collection of JavaScript modules. You can think of them as li
|
||||
|
||||
For example, import Angular's `Component` decorator from the `@angular/core` library like this.
|
||||
|
||||
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
|
||||
<code-example path="architecture/src/app/app.component.ts" region="import"></code-example>
|
||||
|
||||
You also import NgModules from Angular *libraries* using JavaScript import statements.
|
||||
For example, the following code imports the `BrowserModule` NgModule from the `platform-browser` library.
|
||||
|
||||
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module" linenums="false"></code-example>
|
||||
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module"></code-example>
|
||||
|
||||
In the example of the simple root module above, the application module needs material from within
|
||||
`BrowserModule`. To access that material, add it to the `@NgModule` metadata `imports` like this.
|
||||
|
||||
<code-example path="architecture/src/app/mini-app.ts" region="ngmodule-imports" linenums="false"></code-example>
|
||||
<code-example path="architecture/src/app/mini-app.ts" region="ngmodule-imports"></code-example>
|
||||
|
||||
In this way you're using the Angular and JavaScript module systems *together*. Although it's easy to confuse the two systems, which share the common vocabulary of "imports" and "exports", you will become familiar with the different contexts in which they are used.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Introduction to services and dependency injection
|
||||
|
||||
*Service* is a broad category encompassing any value, function, or feature that an app needs.
|
||||
A service is typically a class with a narrow, well-defined purpose.
|
||||
A service is typically a class with a narrow, well-defined purpose.
|
||||
It should do something specific and do it well.
|
||||
|
||||
Angular distinguishes components from services to increase modularity and reusability.
|
||||
@@ -14,9 +14,9 @@ in order to mediate between the view (rendered by the template)
|
||||
and the application logic (which often includes some notion of a *model*).
|
||||
|
||||
A component can delegate certain tasks to services, such as fetching data from the server,
|
||||
validating user input, or logging directly to the console.
|
||||
validating user input, or logging directly to the console.
|
||||
By defining such processing tasks in an *injectable service class*, you make those tasks
|
||||
available to any component.
|
||||
available to any component.
|
||||
You can also make your app more adaptable by injecting different providers of the same kind of service,
|
||||
as appropriate in different circumstances.
|
||||
|
||||
@@ -28,21 +28,21 @@ available to components through *dependency injection*.
|
||||
|
||||
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" header="src/app/logger.service.ts (class)" region="class"></code-example>
|
||||
<code-example path="architecture/src/app/logger.service.ts" 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.
|
||||
|
||||
<code-example path="architecture/src/app/hero.service.ts" linenums="false" header="src/app/hero.service.ts (class)" region="class"></code-example>
|
||||
<code-example path="architecture/src/app/hero.service.ts" header="src/app/hero.service.ts (class)" region="class"></code-example>
|
||||
|
||||
## Dependency injection (DI)
|
||||
|
||||
<img src="generated/images/guide/architecture/dependency-injection.png" alt="Service" class="left">
|
||||
|
||||
DI is wired into the Angular framework and used everywhere to provide new components with the services or other things they need.
|
||||
Components consume services; that is, you can *inject* a service into a component, giving the component access to that service class.
|
||||
Components consume services; that is, you can *inject* a service into a component, giving the component access to that service class.
|
||||
|
||||
To define a class as a service in Angular, use the `@Injectable()` decorator to provide the metadata that allows Angular to inject it into a component as a *dependency*.
|
||||
Similarly, use the `@Injectable()` decorator to indicate that a component or other class (such as another service, a pipe, or an NgModule) *has* a dependency.
|
||||
To define a class as a service in Angular, use the `@Injectable()` decorator to provide the metadata that allows Angular to inject it into a component as a *dependency*.
|
||||
Similarly, use the `@Injectable()` decorator to indicate that a component or other class (such as another service, a pipe, or an NgModule) *has* a dependency.
|
||||
|
||||
* The *injector* is the main mechanism. Angular creates an application-wide injector for you during the bootstrap process, and additional injectors as needed. You don't have to create injectors.
|
||||
|
||||
@@ -50,19 +50,19 @@ Similarly, use the `@Injectable()` decorator to indicate that a component or oth
|
||||
|
||||
* A *provider* is an object that tells an injector how to obtain or create a dependency.
|
||||
|
||||
For any dependency that you need in your app, you must register a provider with the app's injector,
|
||||
so that the injector can use the provider to create new instances.
|
||||
For any dependency that you need in your app, you must register a provider with the app's injector,
|
||||
so that the injector can use the provider to create new instances.
|
||||
For a service, the provider is typically the service class itself.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
A dependency doesn't have to be a service—it could be a function, for example, or a value.
|
||||
A dependency doesn't have to be a service—it could be a function, for example, or a value.
|
||||
|
||||
</div>
|
||||
|
||||
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" header="src/app/hero-list.component.ts (constructor)" region="ctor"></code-example>
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" 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.
|
||||
|
||||
@@ -78,26 +78,26 @@ The process of `HeroService` injection looks something like this.
|
||||
|
||||
You must register at least one *provider* of any service you are going to use.
|
||||
The provider can be part of the service's own metadata, making that service available everywhere,
|
||||
or you can register providers with specific modules or components.
|
||||
or you can register providers with specific modules or components.
|
||||
You register providers in the metadata of the service (in the `@Injectable()` decorator),
|
||||
or in the `@NgModule()` or `@Component()` metadata
|
||||
or in the `@NgModule()` or `@Component()` metadata
|
||||
|
||||
* By default, the Angular CLI command [`ng generate service`](cli/generate) registers a provider with the root injector for your service by including provider metadata in the `@Injectable()` decorator. The tutorial uses this method to register the provider of HeroService class definition.
|
||||
|
||||
```
|
||||
```
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
```
|
||||
```
|
||||
|
||||
When you provide the service at the root level, Angular creates a single, shared instance of `HeroService`
|
||||
and injects it into any class that asks for it.
|
||||
and injects it into any class that asks for it.
|
||||
Registering the provider in the `@Injectable()` metadata also allows Angular to optimize an app
|
||||
by removing the service from the compiled app if it isn't used.
|
||||
by removing the service from the compiled app if it isn't used.
|
||||
|
||||
* When you register a provider with a [specific NgModule](guide/architecture-modules), the same instance of a service is available to all components in that NgModule. To register at this level, use the `providers` property of the `@NgModule()` decorator,
|
||||
|
||||
```
|
||||
```
|
||||
@NgModule({
|
||||
providers: [
|
||||
BackendService,
|
||||
@@ -105,12 +105,12 @@ or in the `@NgModule()` or `@Component()` metadata
|
||||
],
|
||||
...
|
||||
})
|
||||
```
|
||||
```
|
||||
|
||||
* When you register a provider at the component level, you get a new instance of the
|
||||
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.
|
||||
|
||||
<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>
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" 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.
|
||||
|
||||
@@ -37,13 +37,13 @@ This page demonstrates building a simple _appHighlight_ attribute
|
||||
directive to set an element's background color
|
||||
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" header="src/app/app.component.html (applied)" region="applied"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.1.html" header="src/app/app.component.html (applied)" region="applied"></code-example>
|
||||
|
||||
{@a write-directive}
|
||||
|
||||
Please note that directives _do not_ support namespaces.
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.avoid.html" linenums="false" header="src/app/app.component.avoid.html (unsupported)" region="unsupported"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.avoid.html" header="src/app/app.component.avoid.html (unsupported)" region="unsupported"></code-example>
|
||||
|
||||
### Write the directive code
|
||||
|
||||
@@ -101,7 +101,7 @@ Now edit the generated `src/app/highlight.directive.ts` to look as follows:
|
||||
The `import` statement specifies an additional `ElementRef` symbol from the Angular `core` library:
|
||||
|
||||
You use the `ElementRef` in the directive's constructor
|
||||
to [inject](guide/dependency-injection) a reference to the host DOM element,
|
||||
to [inject](guide/dependency-injection) a reference to the host DOM element,
|
||||
the element to which you applied `appHighlight`.
|
||||
|
||||
`ElementRef` grants direct access to the host DOM element
|
||||
@@ -140,12 +140,12 @@ and respond by setting or clearing the highlight color.
|
||||
|
||||
Begin by adding `HostListener` to the list of imported symbols.
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
||||
|
||||
Then add two eventhandlers that respond when the mouse enters or leaves,
|
||||
each adorned by the `HostListener` decorator.
|
||||
|
||||
<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>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (mouse-methods)" region="mouse-methods"></code-example>
|
||||
|
||||
The `@HostListener` decorator lets you subscribe to events of the DOM
|
||||
element that hosts an attribute directive, the `<p>` in this case.
|
||||
@@ -166,7 +166,7 @@ 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 revised constructor simply declares the injected `el: ElementRef`.
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (constructor)" region="ctor"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (constructor)" region="ctor"></code-example>
|
||||
|
||||
Here's the updated directive in full:
|
||||
|
||||
@@ -187,11 +187,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.
|
||||
|
||||
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" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
||||
|
||||
Add a `highlightColor` property to the directive class like this:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (highlightColor)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (highlightColor)" region="color"></code-example>
|
||||
|
||||
{@a input}
|
||||
|
||||
@@ -204,19 +204,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:
|
||||
|
||||
<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>
|
||||
<code-example path="attribute-directives/src/app/app.component.1.html" header="src/app/app.component.html (excerpt)" region="color-1"></code-example>
|
||||
|
||||
Add a `color` property to the `AppComponent`.
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.1.ts" linenums="false" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.1.ts" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||
|
||||
Let it control the highlight color with a property binding.
|
||||
|
||||
<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>
|
||||
<code-example path="attribute-directives/src/app/app.component.1.html" 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.
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||
|
||||
The `[appHighlight]` attribute binding both applies the highlighting directive to the `<p>` element
|
||||
and sets the directive's highlight color with a property binding.
|
||||
@@ -225,7 +225,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.
|
||||
|
||||
<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>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" 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.
|
||||
|
||||
@@ -237,23 +237,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`.
|
||||
|
||||
<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>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" header="src/app/highlight.directive.ts (color property with alias)" region="color"></code-example>
|
||||
|
||||
_Inside_ the directive the property is known as `highlightColor`.
|
||||
_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:
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.html" 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.
|
||||
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" header="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" header="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter"></code-example>
|
||||
|
||||
Here's the latest version of the directive class.
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" header="src/app/highlight.directive.ts (excerpt)"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" header="src/app/highlight.directive.ts (excerpt)"></code-example>
|
||||
|
||||
## Write a harness to try it
|
||||
|
||||
@@ -263,11 +263,11 @@ lets you pick the highlight color with a radio button and bind your color choice
|
||||
|
||||
Update <code>app.component.html</code> as follows:
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (v2)" region="v2"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (v2)" region="v2"></code-example>
|
||||
|
||||
Revise the `AppComponent.color` so that it has no initial value.
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.ts" linenums="false" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.ts" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||
|
||||
Here are the harness and directive in action.
|
||||
|
||||
@@ -287,12 +287,12 @@ Let the template developer set the default color.
|
||||
|
||||
Add a second **input** property to `HighlightDirective` called `defaultColor`:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (defaultColor)" region="defaultColor"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" 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`,
|
||||
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" header="src/app/highlight.directive.ts (mouse-enter)" region="mouse-enter"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" 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?
|
||||
|
||||
@@ -300,7 +300,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`
|
||||
and fall back to "violet" as the default color.
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (defaultColor)" region="defaultColor"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (defaultColor)" region="defaultColor"></code-example>
|
||||
|
||||
Angular knows that the `defaultColor` binding belongs to the `HighlightDirective`
|
||||
because you made it _public_ with the `@Input` decorator.
|
||||
@@ -342,11 +342,11 @@ You can also experience and download the <live-example title="Attribute Directiv
|
||||
In this demo, the `highlightColor` property is an ***input*** property of
|
||||
the `HighlightDirective`. You've seen it applied without an alias:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
||||
|
||||
You've seen it with an alias:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
||||
|
||||
Either way, the `@Input` decorator tells Angular that this property is
|
||||
_public_ and available for binding by a parent component.
|
||||
@@ -378,7 +378,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:
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.html" 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 template and its component trust each other.
|
||||
|
||||
@@ -106,19 +106,16 @@ 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.
|
||||
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" header="src/app/item.directive.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="bootstrapping/src/app/item.directive.ts" region="directive" header="src/app/item.directive.ts"></code-example>
|
||||
|
||||
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:
|
||||
|
||||
<code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" header="src/app/app.module.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" header="src/app/app.module.ts"></code-example>
|
||||
|
||||
And in the same file, add it to the `@NgModule` `declarations` array:
|
||||
|
||||
<code-example path="bootstrapping/src/app/app.module.ts" region="declarations" header="src/app/app.module.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="bootstrapping/src/app/app.module.ts" region="declarations" header="src/app/app.module.ts"></code-example>
|
||||
|
||||
|
||||
Now you could use your `ItemDirective` in a component. This example uses `AppModule`, but you'd do it the same way for a feature module. For more about directives, see [Attribute Directives](guide/attribute-directives) and [Structural Directives](guide/structural-directives). You'd also use the same technique for [pipes](guide/pipes) and components.
|
||||
|
||||
@@ -527,7 +527,7 @@ If you are not using the CLI, add your polyfill scripts directly to the host web
|
||||
|
||||
For example:
|
||||
|
||||
<code-example header="src/index.html" language="html" linenums="false">
|
||||
<code-example header="src/index.html" language="html">
|
||||
<!-- pre-zone polyfills -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
<script src="node_modules/web-animations-js/web-animations.min.js"></script>
|
||||
|
||||
@@ -191,7 +191,7 @@ For our example builder, we expect the `options` value to be a `JsonObject` with
|
||||
|
||||
We can provide the following schema for type validation of these values.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example format="." language="json">
|
||||
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
@@ -222,7 +222,7 @@ To link our builder implementation with its schema and name, we need to create a
|
||||
|
||||
Create a file named `builders.json` file that looks like this.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example format="." language="json">
|
||||
|
||||
{
|
||||
"builders": {
|
||||
@@ -238,7 +238,7 @@ Create a file named `builders.json` file that looks like this.
|
||||
|
||||
In the `package.json` file, add a `builders` key that tells the Architect tool where to find our builder definition file.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example format="." language="json">
|
||||
|
||||
{
|
||||
"name": "@example/command-runner",
|
||||
@@ -257,7 +257,7 @@ The first part of this is the package name (resolved using node resolution), an
|
||||
|
||||
Using one of our `options` is very straightforward, we did this in the previous section when we accessed `options.command`.
|
||||
|
||||
<code-example format="." language="typescript" linenums="false">
|
||||
<code-example format="." language="typescript">
|
||||
context.reportStatus(`Executing "${options.command}"...`);
|
||||
const child = childProcess.spawn(options.command, options.args, { stdio: 'pipe' });
|
||||
|
||||
@@ -274,7 +274,7 @@ The Architect tool uses the target definition to resolve input options for a giv
|
||||
The `angular.json` file has a section for each project, and the "architect" section of each project configures targets for builders used by CLI commands such as 'build', 'test', and 'lint'.
|
||||
By default, for example, the `build` command runs the builder `@angular-devkit/build-angular:browser` to perform the build task, and passes in default option values as specified for the `build` target in `angular.json`.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example format="." language="json">
|
||||
{
|
||||
"myApp": {
|
||||
...
|
||||
@@ -361,7 +361,7 @@ npm install @example/command-runner
|
||||
|
||||
If we create a new project with `ng new builder-test`, the generated `angular.json` file looks something like this, with only default builder configurations.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example format="." language="json">
|
||||
|
||||
{
|
||||
// ...
|
||||
@@ -413,7 +413,7 @@ We need to update the `angular.json` file to add a target for this builder to th
|
||||
|
||||
* The configurations key is optional, we'll leave it out for now.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example format="." language="json">
|
||||
|
||||
{
|
||||
"projects": {
|
||||
@@ -495,7 +495,7 @@ Use integration testing for your builder, so that you can use the Architect sche
|
||||
Here’s an example of a test that runs the command builder.
|
||||
The test uses the builder to run the `ls` command, then validates that it ran successfully and listed the proper files.
|
||||
|
||||
<code-example format="." language="typescript" linenums="false">
|
||||
<code-example format="." language="typescript">
|
||||
|
||||
import { Architect, ArchitectHost } from '@angular-devkit/architect';
|
||||
import { TestingArchitectHost } from '@angular-devkit/architect/testing';
|
||||
@@ -592,4 +592,4 @@ The CLI Builder API provides a new way of changing the behavior of the Angular C
|
||||
|
||||
* We recommend that you use integration tests to test Architect builders. You can use unit tests to validate the logic that the builder executes.
|
||||
|
||||
* If your builder returns an Observable, it should clean up in the teardown logic of that Observable.
|
||||
* If your builder returns an Observable, it should clean up in the teardown logic of that Observable.
|
||||
|
||||
@@ -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.
|
||||
|
||||
<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>
|
||||
<code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="page-animations" language="typescript"></code-example>
|
||||
|
||||
## 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.
|
||||
|
||||
<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>
|
||||
<code-example path="animations/src/app/hero-list-groups.component.ts" region="animationdef" header="src/app/hero-list-groups.component.ts (excerpt)" language="typescript"></code-example>
|
||||
|
||||
## Sequential vs. parallel animations
|
||||
|
||||
@@ -74,7 +74,7 @@ The HTML template contains a trigger called `filterAnimation`.
|
||||
|
||||
The component file contains three transitions.
|
||||
|
||||
<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>
|
||||
<code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="filter-animations" language="typescript"></code-example>
|
||||
|
||||
The animation does the following:
|
||||
|
||||
@@ -101,4 +101,4 @@ You may also be interested in the following:
|
||||
* [Introduction to Angular animations](guide/animations)
|
||||
* [Transition and triggers](guide/transition-and-triggers)
|
||||
* [Reusable animations](guide/reusable-animations)
|
||||
* [Route transition animations](guide/route-animations)
|
||||
* [Route transition animations](guide/route-animations)
|
||||
|
||||
@@ -21,8 +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.
|
||||
Usually you give it one string, as in the following example:
|
||||
|
||||
<code-example path="component-styles/src/app/hero-app.component.ts" header="src/app/hero-app.component.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="component-styles/src/app/hero-app.component.ts" header="src/app/hero-app.component.ts"></code-example>
|
||||
|
||||
## Style scope
|
||||
|
||||
@@ -71,8 +70,7 @@ Use the `:host` pseudo-class selector to target styles in the element that *host
|
||||
targeting elements *inside* the component's template).
|
||||
|
||||
|
||||
<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 path="component-styles/src/app/hero-details.component.css" region="host" header="src/app/hero-details.component.css"></code-example>
|
||||
|
||||
The `:host` selector is the only way to target the host element. You can't reach
|
||||
the host element from inside the component with other selectors because it's not part of the
|
||||
@@ -83,8 +81,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.
|
||||
|
||||
<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 path="component-styles/src/app/hero-details.component.css" region="hostfunction" header="src/app/hero-details.component.css"></code-example>
|
||||
|
||||
### :host-context
|
||||
|
||||
@@ -99,8 +96,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
|
||||
if some ancestor element has the CSS class `theme-light`.
|
||||
|
||||
<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 path="component-styles/src/app/hero-details.component.css" region="hostcontext" header="src/app/hero-details.component.css"></code-example>
|
||||
|
||||
### (deprecated) `/deep/`, `>>>`, and `::ng-deep`
|
||||
|
||||
@@ -115,9 +111,7 @@ can bleed into other components.
|
||||
The following example targets all `<h3>` elements, from the host element down
|
||||
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" header="src/app/hero-details.component.css" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="deep" header="src/app/hero-details.component.css"></code-example>
|
||||
|
||||
The `/deep/` combinator also has the aliases `>>>`, and `::ng-deep`.
|
||||
|
||||
@@ -304,8 +298,7 @@ Choose from the following modes:
|
||||
|
||||
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" header="src/app/quest-summary.component.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts"></code-example>
|
||||
|
||||
`ShadowDom` view encapsulation only works on browsers that have native support
|
||||
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
|
||||
|
||||
@@ -21,18 +21,14 @@ constructor, and lets the framework provide them.
|
||||
|
||||
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" header="src/app/app.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/app.component.ts" region="ctor" header="src/app/app.component.ts"></code-example>
|
||||
|
||||
|
||||
`UserContext` in turn depends on both `LoggerService` and
|
||||
`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" header="user-context.service.ts (injection)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/user-context.service.ts" region="injectables" header="user-context.service.ts (injection)"></code-example>
|
||||
|
||||
|
||||
When Angular creates `AppComponent`, the DI framework creates an instance of `LoggerService` and starts to create `UserContextService`.
|
||||
@@ -185,17 +181,13 @@ This `HeroBiosAndContactsComponent` is a revision of `HeroBiosComponent` which y
|
||||
|
||||
Focus on the template:
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="template" header="dependency-injection-in-action/src/app/hero-bios.component.ts"></code-example>
|
||||
|
||||
Now there's a new `<hero-contact>` element between the `<hero-bio>` tags.
|
||||
Angular *projects*, or *transcludes*, the corresponding `HeroContactComponent` into the `HeroBioComponent` view,
|
||||
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" header="src/app/hero-bio.component.ts (template)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-bio.component.ts" region="template" header="src/app/hero-bio.component.ts (template)"></code-example>
|
||||
|
||||
The result is shown below, with the hero's telephone number from `HeroContactComponent` projected above the hero description.
|
||||
|
||||
@@ -212,9 +204,7 @@ Here's `HeroContactComponent`, which demonstrates the qualifying decorators.
|
||||
|
||||
Focus on the constructor parameters.
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="ctor-params" header="src/app/hero-contact.component.ts"></code-example>
|
||||
|
||||
The `@Host()` function decorating the `heroCache` constructor property ensures that
|
||||
you get a reference to the cache service from the parent `HeroBioComponent`.
|
||||
@@ -299,9 +289,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,
|
||||
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" header="src/app/app.component.html (highlight)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/app.component.html" region="highlight" header="src/app/app.component.html (highlight)"></code-example>
|
||||
|
||||
|
||||
The following image shows the effect of mousing over the `<hero-bios-and-contacts>` tag.
|
||||
@@ -325,9 +313,7 @@ Angular passes this token to the injector and assigns the result to the paramete
|
||||
The following is a typical example.
|
||||
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="ctor" header="src/app/hero-bios.component.ts (component constructor injection)"></code-example>
|
||||
|
||||
|
||||
Angular asks the injector for the service associated with `LoggerService`
|
||||
@@ -386,9 +372,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.
|
||||
|
||||
<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 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"></code-example>
|
||||
|
||||
* The first provides an existing instance of the `Hero` class to use for the `Hero` token, rather than
|
||||
requiring the injector to create a new instance with `new` or use its own cached instance.
|
||||
@@ -427,9 +411,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`.
|
||||
|
||||
<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 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"></code-example>
|
||||
|
||||
The first provider is the *de-sugared*, expanded form of the most typical case in which the
|
||||
class to be created (`HeroService`) is also the provider's dependency injection token.
|
||||
@@ -448,9 +430,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:
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/date-logger.service.ts" region="date-logger-service" header="src/app/date-logger.service.ts"></code-example>
|
||||
|
||||
{@a useexisting}
|
||||
|
||||
@@ -472,15 +452,11 @@ 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:
|
||||
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="src/app/minimal-logger.service.ts"></code-example>
|
||||
|
||||
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" header="src/app/hero-of-the-month.component.ts (minimal version)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<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)"></code-example>
|
||||
|
||||
The `HeroOfTheMonthComponent` constructor's `logger` parameter is typed as `MinimalLogger`, so only the `logs` and `logInfo` members are visible in a TypeScript-aware editor.
|
||||
|
||||
@@ -532,9 +508,7 @@ The `runnersUpFactory()` returns the *provider factory function*, which can use
|
||||
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" header="runners-up.ts (excerpt)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/runners-up.ts" region="factory-synopsis" header="runners-up.ts (excerpt)"></code-example>
|
||||
|
||||
The provider factory function (returned by `runnersUpFactory()`) returns the actual dependency object,
|
||||
the string of names.
|
||||
@@ -578,9 +552,7 @@ as the token for a provider of `LoggerService`.
|
||||
|
||||
`MinimalLogger` is an abstract class.
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="dependency-injection-in-action/src/app/minimal-logger.service.ts"></code-example>
|
||||
|
||||
An abstract class is usually a base class that you can extend.
|
||||
In this app, however there is no class that inherits from `MinimalLogger`.
|
||||
@@ -606,9 +578,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*.
|
||||
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" header="dependency-injection-in-action/src/app/minimal-logger.service.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<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"></code-example>
|
||||
|
||||
Notice that it doesn't have any members. It never grows no matter how many members you add to the class,
|
||||
as long as those members are typed but not implemented.
|
||||
@@ -635,15 +605,11 @@ another token that happens to have the same name.
|
||||
You encountered them twice in the *Hero of the Month* example,
|
||||
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" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<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"></code-example>
|
||||
|
||||
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" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<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"></code-example>
|
||||
|
||||
The type parameter, while optional, conveys the dependency's type to developers and tooling.
|
||||
The token description is another developer aid.
|
||||
@@ -733,9 +699,7 @@ appear *above* the class definition.
|
||||
|
||||
Break the circularity with `forwardRef`.
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="parent-finder.component.ts (AlexComponent providers)"></code-example>
|
||||
|
||||
|
||||
<!--- Waiting for good examples
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
Application components often need to share information.
|
||||
You can often use loosely coupled techniques for sharing information,
|
||||
such as data binding and service sharing,
|
||||
but sometimes it makes sense for one component to have a direct reference to another component.
|
||||
such as data binding and service sharing,
|
||||
but sometimes it makes sense for one component to have a direct reference to another component.
|
||||
You need a direct reference, for instance, to access values or call methods on that component.
|
||||
|
||||
Obtaining a component reference is a bit tricky in Angular.
|
||||
Angular components themselves do not have a tree that you can
|
||||
Angular components themselves do not have a tree that you can
|
||||
inspect or navigate programmatically. The parent-child relationship is indirect,
|
||||
established through the components' [view objects](guide/glossary#view).
|
||||
|
||||
Each component has a *host view*, and can have additional *embedded views*.
|
||||
Each component has a *host view*, and can have additional *embedded views*.
|
||||
An embedded view in component A is the
|
||||
host view of component B, which can in turn have embedded view.
|
||||
This means that there is a [view hierarchy](guide/glossary#view-hierarchy) for each component,
|
||||
@@ -40,18 +40,14 @@ In the following example, the parent `AlexComponent` has several children includ
|
||||
{@a alex}
|
||||
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-1" header="parent-finder.component.ts (AlexComponent v.1)"></code-example>
|
||||
|
||||
|
||||
|
||||
*Cathy* reports whether or not she has access to *Alex*
|
||||
after injecting an `AlexComponent` into her constructor:
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="cathy" header="parent-finder.component.ts (CathyComponent)"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -98,17 +94,13 @@ inject its parent via the parent's base class*.
|
||||
The sample's `CraigComponent` explores this question. [Looking back](#alex),
|
||||
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" header="parent-finder.component.ts (Alex class signature)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<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)"></code-example>
|
||||
|
||||
|
||||
|
||||
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" header="parent-finder.component.ts (CraigComponent)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="craig" header="parent-finder.component.ts (CraigComponent)"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -138,9 +130,7 @@ and add that provider to the `providers` array of the `@Component()` metadata fo
|
||||
{@a alex-providers}
|
||||
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="parent-finder.component.ts (AlexComponent providers)"></code-example>
|
||||
|
||||
|
||||
[Parent](#parent-token) is the provider's class interface token.
|
||||
@@ -149,9 +139,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,
|
||||
the same way you've done it before.
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="carol-class" header="parent-finder.component.ts (CarolComponent class)"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -177,9 +165,7 @@ That means he must both *inject* the `Parent` class interface to get *Alice* and
|
||||
|
||||
Here's *Barry*.
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="barry" header="parent-finder.component.ts (BarryComponent)"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -229,9 +215,7 @@ You [learned earlier](guide/dependency-injection-in-action#class-interface) that
|
||||
|
||||
The example defines a `Parent` class interface.
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="parent" header="parent-finder.component.ts (Parent class-interface)"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -241,9 +225,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.
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-class-signature" header="parent-finder.component.ts (AliceComponent class signature)"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -251,9 +233,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,
|
||||
its class signature doesn't mention `Parent`.
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" header="parent-finder.component.ts (AlexComponent class signature)"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -277,21 +257,15 @@ 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,
|
||||
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" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<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"></code-example>
|
||||
|
||||
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" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<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"></code-example>
|
||||
|
||||
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" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<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"></code-example>
|
||||
|
||||
|
||||
You can do better. The current version of the helper function can only alias the `Parent` class interface.
|
||||
@@ -299,14 +273,10 @@ 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.
|
||||
|
||||
<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 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"></code-example>
|
||||
|
||||
|
||||
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" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<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"></code-example>
|
||||
|
||||
|
||||
@@ -68,13 +68,11 @@ using the `Logger` token.
|
||||
Another class, `EvenBetterLogger`, might display the user name in the log message.
|
||||
This logger gets the user from an injected `UserService` instance.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="EvenBetterLogger" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="EvenBetterLogger"></code-example>
|
||||
|
||||
The injector needs providers for both this new logging service and its dependent `UserService`. Configure this alternative logger with the `useClass` provider-definition key, like `BetterLogger`. The following array specifies both providers in the `providers` metadata option of the parent module or component.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-5" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-5"></code-example>
|
||||
|
||||
{@a aliased-class-providers}
|
||||
|
||||
@@ -92,13 +90,11 @@ when a component asks for either the new or the old logger.
|
||||
|
||||
If you try to alias `OldLogger` to `NewLogger` with `useClass`, you end up with two different `NewLogger` instances in your app.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6a" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6a"></code-example>
|
||||
|
||||
To make sure there is only one instance of `NewLogger`, alias `OldLogger` with the `useExisting` option.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6b" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6b"></code-example>
|
||||
|
||||
{@a value-provider}
|
||||
|
||||
@@ -110,13 +106,11 @@ configure the injector with the `useValue` option
|
||||
|
||||
The following code defines a variable that creates such an object to play the logger role.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="silent-logger" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="silent-logger"></code-example>
|
||||
|
||||
The following provider object uses the `useValue` key to associate the variable with the `Logger` token.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-7" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-7"></code-example>
|
||||
|
||||
{@a non-class-dependencies}
|
||||
|
||||
@@ -130,8 +124,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.
|
||||
They can be object literals, as shown in the following example.
|
||||
|
||||
<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 path="dependency-injection/src/app/app.config.ts" region="config" header="src/app/app.config.ts (excerpt)"></code-example>
|
||||
|
||||
{@a interface-not-valid-token}
|
||||
|
||||
@@ -141,11 +134,9 @@ The `HERO_DI_CONFIG` constant conforms to the `AppConfig` interface.
|
||||
Unfortunately, you cannot use a TypeScript interface as a token.
|
||||
In TypeScript, an interface is a design-time artifact, and doesn't have a runtime representation (token) that the DI framework can use.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9-interface" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9-interface"></code-example>
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-9-ctor-interface" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-9-ctor-interface"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@@ -163,22 +154,19 @@ Another solution to choosing a provider token for non-class dependencies is
|
||||
to define and use an `InjectionToken` object.
|
||||
The following example shows how to define such a token.
|
||||
|
||||
<code-example path="dependency-injection/src/app/app.config.ts" region="token" header="src/app/app.config.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/app.config.ts" region="token" header="src/app/app.config.ts"></code-example>
|
||||
|
||||
The type parameter, while optional, conveys the dependency's type to developers and tooling.
|
||||
The token description is another developer aid.
|
||||
|
||||
Register the dependency provider using the `InjectionToken` object:
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9"></code-example>
|
||||
|
||||
Now you can inject the configuration object into any constructor that needs it, with
|
||||
the help of an `@Inject()` parameter decorator.
|
||||
|
||||
<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 path="dependency-injection/src/app/app.component.2.ts" region="ctor" header="src/app/app.component.ts"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@@ -215,22 +203,19 @@ who is authorized and who isn't.
|
||||
|
||||
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" header="src/app/heroes/hero.service.ts (excerpt)" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.ts" region="internals" header="src/app/heroes/hero.service.ts (excerpt)"></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`.
|
||||
|
||||
A factory provider needs a factory function.
|
||||
|
||||
<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 path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="factory" header="src/app/heroes/hero.service.provider.ts (excerpt)"></code-example>
|
||||
|
||||
Although `HeroService` has no access to `UserService`, the factory function does.
|
||||
You inject both `Logger` and `UserService` into the factory provider
|
||||
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" header="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="provider" header="src/app/heroes/hero.service.provider.ts (excerpt)"></code-example>
|
||||
|
||||
* The `useFactory` field tells Angular that the provider is a factory function whose implementation is `heroServiceFactory`.
|
||||
|
||||
@@ -322,13 +307,13 @@ Thus, services in the NgModule `providers` array or at component level are not t
|
||||
|
||||
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" header="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"></code-example>
|
||||
|
||||
You can then import this module into your application module
|
||||
to make the service available for injection in your app,
|
||||
as in the following 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>
|
||||
<code-example path="dependency-injection/src/app/tree-shaking/app.module.ts" header="src/app/tree-shaking/app.modules.ts"></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.
|
||||
|
||||
@@ -340,11 +325,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.
|
||||
|
||||
<code-example path="dependency-injection/src/app/tree-shaking/service.ts" header="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"></code-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" header="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"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
||||
@@ -196,8 +196,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
|
||||
under test.
|
||||
|
||||
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" header="src/app/test.component.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" header="src/app/test.component.ts"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@@ -259,8 +258,7 @@ In simple examples, the dependency value is an *instance*, and
|
||||
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:
|
||||
|
||||
<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 path="dependency-injection/src/app/injector.component.ts" region="get-hero-service" header="src/app/injector.component.ts"></code-example>
|
||||
|
||||
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,
|
||||
@@ -287,8 +285,7 @@ constructor parameter with `@Optional()`.
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="import-optional">
|
||||
</code-example>
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-10-ctor" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-10-ctor"></code-example>
|
||||
|
||||
When using `@Optional()`, your code must be prepared for a null value. If you
|
||||
don't register a logger provider anywhere, the injector sets the
|
||||
|
||||
@@ -175,7 +175,7 @@ modified to serve `index.html`:
|
||||
* [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown
|
||||
[here](http://stackoverflow.com/a/26152011/2116927):
|
||||
|
||||
<code-example format='.' language="xml" linenums="false">
|
||||
<code-example format='.' language="xml">
|
||||
<system.webServer>
|
||||
<rewrite>
|
||||
<rules>
|
||||
@@ -436,7 +436,7 @@ When you create a production build using [`ng build --prod`](cli/build), the CLI
|
||||
|
||||
The `index.html` file is also modified during the build process to include script tags that enable differential loading. See the sample output below from the `index.html` file produced during a build using `ng build`.
|
||||
|
||||
<code-example language="html" format="." linenums="false">
|
||||
<code-example language="html" format=".">
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
<script src="runtime-es2015.js" type="module"></script>
|
||||
@@ -479,7 +479,7 @@ not IE 9-11 # For IE 9-11 support, remove 'not'.
|
||||
|
||||
The `tsconfig.json` looks like this:
|
||||
|
||||
<code-example language="json" format="." linenums="false">
|
||||
<code-example language="json" format=".">
|
||||
|
||||
{
|
||||
"compileOnSave": false,
|
||||
@@ -550,7 +550,7 @@ To maintain the benefits of differential loading, however, a better option is to
|
||||
|
||||
To do this for `ng serve`, create a new file, `tsconfig-es5.app.json` next to `tsconfig.app.json` with the following content.
|
||||
|
||||
<code-example language="json" format="." linenums="false">
|
||||
<code-example language="json" format=".">
|
||||
|
||||
{
|
||||
"extends": "./tsconfig.app.json",
|
||||
@@ -563,7 +563,7 @@ To do this for `ng serve`, create a new file, `tsconfig-es5.app.json` next to `t
|
||||
|
||||
In `angular.json` add two new configuration sections under the `build` and `serve` targets to point to the new TypeScript configuration.
|
||||
|
||||
<code-example language="json" format="." linenums="false">
|
||||
<code-example language="json" format=".">
|
||||
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
@@ -610,7 +610,7 @@ ng serve --configuration es5
|
||||
|
||||
Create a new file, `tsconfig-es5.spec.json` next to `tsconfig.spec.json` with the following content.
|
||||
|
||||
<code-example language="json" format="." linenums="false">
|
||||
<code-example language="json" format=".">
|
||||
|
||||
{
|
||||
"extends": "./tsconfig.spec.json",
|
||||
@@ -621,7 +621,7 @@ Create a new file, `tsconfig-es5.spec.json` next to `tsconfig.spec.json` with th
|
||||
|
||||
</code-example>
|
||||
|
||||
<code-example language="json" format="." linenums="false">
|
||||
<code-example language="json" format=".">
|
||||
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
@@ -649,7 +649,7 @@ ng test --configuration es5
|
||||
|
||||
Create an [ES5 serve configuration](guide/deployment#configuring-serve-for-es5) as explained above, and configuration an ES5 configuration for the E2E target.
|
||||
|
||||
<code-example language="json" format="." linenums="false">
|
||||
<code-example language="json" format=".">
|
||||
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
|
||||
@@ -507,7 +507,7 @@ public createAndAppendElement() {
|
||||
|
||||
**After:**
|
||||
|
||||
<code-example linenums=false>
|
||||
<code-example>
|
||||
|
||||
public createAndAppendElement() {
|
||||
const el = __ngRendererCreateElement(this.renderer, this.element, 'span');
|
||||
|
||||
@@ -31,7 +31,7 @@ The easiest way to display a component property
|
||||
is to bind the property name through interpolation.
|
||||
With interpolation, you put the property name in the view template, enclosed in double curly braces: `{{myHero}}`.
|
||||
|
||||
Use the CLI command [`ng new displaying-data`](cli/new) to create a workspace and app named `displaying-data`.
|
||||
Use the CLI command [`ng new displaying-data`](cli/new) to create a workspace and app named `displaying-data`.
|
||||
|
||||
Delete the <code>app.component.html</code> file. It is not needed for this example.
|
||||
|
||||
@@ -41,9 +41,7 @@ changing the template and the body of the component.
|
||||
When you're done, it should look like this:
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts">
|
||||
|
||||
</code-example>
|
||||
<code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -53,9 +51,7 @@ The template displays the two component properties using double curly brace
|
||||
interpolation:
|
||||
|
||||
|
||||
<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 path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts (template)" region="template"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -97,9 +93,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:
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/index.html" linenums="false" header="src/index.html (body)" region="body">
|
||||
|
||||
</code-example>
|
||||
<code-example path="displaying-data/src/index.html" header="src/index.html (body)" region="body"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -133,7 +127,7 @@ is simpler without the additional HTML file.
|
||||
In either style, the template data bindings have the same access to the component's properties.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
||||
By default, the Angular CLI command [`ng generate component`](cli/generate) generates components with a template file. You can override that with:
|
||||
|
||||
<code-example hideCopy language="sh" class="code-shell">
|
||||
@@ -148,9 +142,7 @@ In either style, the template data bindings have the same access to the componen
|
||||
Although this example uses variable assignment to initialize the components, you could instead declare and initialize the properties using a constructor:
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/app-ctor.component.1.ts" linenums="false" region="class">
|
||||
|
||||
</code-example>
|
||||
<code-example path="displaying-data/src/app/app-ctor.component.1.ts" region="class"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -163,9 +155,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.
|
||||
|
||||
|
||||
<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 path="displaying-data/src/app/app.component.2.ts" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -173,9 +163,7 @@ Now use the Angular `ngFor` directive in the template to display
|
||||
each item in the `heroes` list.
|
||||
|
||||
|
||||
<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 path="displaying-data/src/app/app.component.2.ts" header="src/app/app.component.ts (template)" region="template"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -184,9 +172,7 @@ in the `<li>` element is the Angular "repeater" directive.
|
||||
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" header="src/app/app.component.ts (li)" region="li">
|
||||
|
||||
</code-example>
|
||||
<code-example path="displaying-data/src/app/app.component.2.ts" header="src/app/app.component.ts (li)" region="li"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -251,9 +237,7 @@ of hero names into an array of `Hero` objects. For that you'll need a `Hero` cla
|
||||
With the following code:
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/hero.ts" linenums="false" header="src/app/hero.ts">
|
||||
|
||||
</code-example>
|
||||
<code-example path="displaying-data/src/app/hero.ts" header="src/app/hero.ts"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -265,9 +249,7 @@ The declaration of the constructor parameters takes advantage of a TypeScript sh
|
||||
Consider the first parameter:
|
||||
|
||||
|
||||
<code-example path="displaying-data/src/app/hero.ts" linenums="false" header="src/app/hero.ts (id)" region="id">
|
||||
|
||||
</code-example>
|
||||
<code-example path="displaying-data/src/app/hero.ts" header="src/app/hero.ts (id)" region="id"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -285,9 +267,7 @@ After importing the `Hero` class, the `AppComponent.heroes` property can return
|
||||
of `Hero` objects:
|
||||
|
||||
|
||||
<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 path="displaying-data/src/app/app.component.3.ts" header="src/app/app.component.ts (heroes)" region="heroes"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -296,9 +276,7 @@ At the moment it displays the hero's `id` and `name`.
|
||||
Fix that to display only the hero's `name` property.
|
||||
|
||||
|
||||
<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 path="displaying-data/src/app/app.component.3.ts" header="src/app/app.component.ts (template)" region="template"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -316,9 +294,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:
|
||||
|
||||
|
||||
<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 path="displaying-data/src/app/app.component.ts" header="src/app/app.component.ts (message)" region="message"></code-example>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -665,7 +665,7 @@ Examine the `src/app/app.component.ts` file which defines two nested _#docregion
|
||||
|
||||
The inner, `class-skeleton` region appears twice, once to capture the code that opens the class definition and once to capture the code that closes the class definition.
|
||||
|
||||
<code-example linenums="false">
|
||||
<code-example>
|
||||
// #docplaster
|
||||
...
|
||||
// #docregion class, class-skeleton
|
||||
|
||||
@@ -35,9 +35,7 @@ The ad banner uses a helper directive called `AdDirective` to
|
||||
mark valid insertion points in the template.
|
||||
|
||||
|
||||
<code-example path="dynamic-component-loader/src/app/ad.directive.ts" header="src/app/ad.directive.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dynamic-component-loader/src/app/ad.directive.ts" header="src/app/ad.directive.ts"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -62,9 +60,7 @@ To apply the `AdDirective`, recall the selector from `ad.directive.ts`,
|
||||
where to dynamically load components.
|
||||
|
||||
|
||||
<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 path="dynamic-component-loader/src/app/ad-banner.component.ts" region="ad-host" header="src/app/ad-banner.component.ts (template)"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -91,9 +87,7 @@ With its `getAds()` method, `AdBannerComponent` cycles through the array of `AdI
|
||||
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" header="src/app/ad-banner.component.ts (excerpt)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="class" header="src/app/ad-banner.component.ts (excerpt)"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -150,9 +144,7 @@ dynamically loaded components since they load at runtime.
|
||||
To ensure that the compiler still generates a factory,
|
||||
add dynamically loaded components to the `NgModule`'s `entryComponents` array:
|
||||
|
||||
<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 path="dynamic-component-loader/src/app/app.module.ts" region="entry-components" header="src/app/app.module.ts (entry components)"></code-example>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -77,18 +77,14 @@ appropriate controls dynamically.
|
||||
via the `type` property.
|
||||
|
||||
|
||||
<code-example path="dynamic-form/src/app/question-textbox.ts" header="src/app/question-textbox.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dynamic-form/src/app/question-textbox.ts" header="src/app/question-textbox.ts"></code-example>
|
||||
|
||||
|
||||
|
||||
`DropdownQuestion` presents a list of choices in a select box.
|
||||
|
||||
|
||||
<code-example path="dynamic-form/src/app/question-dropdown.ts" header="src/app/question-dropdown.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dynamic-form/src/app/question-dropdown.ts" header="src/app/question-dropdown.ts"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -97,9 +93,7 @@ In a nutshell, the form group consumes the metadata from the question model and
|
||||
allows you to specify default values and validation rules.
|
||||
|
||||
|
||||
<code-example path="dynamic-form/src/app/question-control.service.ts" header="src/app/question-control.service.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dynamic-form/src/app/question-control.service.ts" header="src/app/question-control.service.ts"></code-example>
|
||||
|
||||
{@a form-component}
|
||||
|
||||
|
||||
@@ -66,8 +66,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:
|
||||
|
||||
|
||||
<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 path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="customer-dashboard-component" header="src/app/customer-dashboard/customer-dashboard.module.ts"></code-example>
|
||||
|
||||
|
||||
|
||||
@@ -77,8 +76,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:
|
||||
|
||||
<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 path="feature-modules/src/app/app.module.ts" region="app-module" header="src/app/app.module.ts"></code-example>
|
||||
|
||||
|
||||
Now the `AppModule` knows about the feature module. If you were to add any service providers to the feature module, `AppModule` would know about those too, as would any other feature modules. However, NgModules don’t expose their components.
|
||||
@@ -88,21 +86,18 @@ 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:
|
||||
|
||||
<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 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"></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 `CustomerDashboardComponent`:
|
||||
|
||||
<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 path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="component-exports" header="src/app/customer-dashboard/customer-dashboard.module.ts"></code-example>
|
||||
|
||||
|
||||
|
||||
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" header="src/app/app.component.html" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="feature-modules/src/app/app.component.html" region="app-component-template" header="src/app/app.component.html"></code-example>
|
||||
|
||||
|
||||
Now, in addition to the title that renders by default, the `CustomerDashboardComponent` template renders too:
|
||||
|
||||
@@ -4,7 +4,7 @@ You develop applications in the context of an Angular [workspace](guide/glossary
|
||||
|
||||
The Angular CLI `ng new` command creates a workspace.
|
||||
|
||||
<code-example language="bash" linenums="false">
|
||||
<code-example language="bash">
|
||||
ng new <my-project>
|
||||
</code-example>
|
||||
|
||||
@@ -111,7 +111,7 @@ An `e2e/` folder at the top level contains source files for a set of end-to-end
|
||||
|
||||
For a multi-project workspace, application-specific end-to-end tests are in the project root, under `projects/project-name/e2e/`.
|
||||
|
||||
<code-example language="none" linenums="false">
|
||||
<code-example language="none">
|
||||
e2e/
|
||||
src/ (end-to-end tests for my-app)
|
||||
app.e2e-spec.ts
|
||||
@@ -131,13 +131,13 @@ A multi-project workspace is suitable for an enterprise that uses a single repos
|
||||
If you intend to have multiple projects in a workspace, you can skip the initial application generation when you create the workspace, and give the workspace a unique name.
|
||||
The following command creates a workspace with all of the workspace-wide configuration files, but no root-level application.
|
||||
|
||||
<code-example language="bash" linenums="false">
|
||||
<code-example language="bash">
|
||||
ng new my-workspace --createApplication="false"
|
||||
</code-example>
|
||||
|
||||
You can then generate apps and libraries with names that are unique within the workspace.
|
||||
|
||||
<code-example language="bash" linenums="false">
|
||||
<code-example language="bash">
|
||||
cd my-workspace
|
||||
ng generate application my-first-app
|
||||
</code-example>
|
||||
@@ -148,7 +148,7 @@ The first explicitly generated application goes into the `projects/` folder alon
|
||||
Newly generated libraries are also added under `projects/`.
|
||||
When you create projects this way, the file structure of the workspace is entirely consistent with the structure of the [workspace configuration file](guide/workspace-config), `angular.json`.
|
||||
|
||||
<code-example language="none" linenums="false">
|
||||
<code-example language="none">
|
||||
my-workspace/
|
||||
... (workspace-wide config files)
|
||||
projects/ (generated applications and libraries)
|
||||
|
||||
@@ -29,9 +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.
|
||||
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" header="template/hero-form-template.component.html (name)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<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)"></code-example>
|
||||
|
||||
|
||||
Note the following:
|
||||
@@ -92,8 +90,7 @@ built-in validators—this time, in function form. See below:
|
||||
|
||||
{@a reactive-component-class}
|
||||
|
||||
<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 path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="form-group" header="reactive/hero-form-reactive.component.ts (validator functions)"></code-example>
|
||||
|
||||
Note that:
|
||||
|
||||
@@ -106,8 +103,7 @@ for the template.
|
||||
|
||||
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" header="reactive/hero-form-reactive.component.html (name with error msg)" linenums="false">
|
||||
</code-example>
|
||||
<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)"></code-example>
|
||||
|
||||
Key takeaways:
|
||||
|
||||
@@ -125,8 +121,7 @@ Consider the `forbiddenNameValidator` function from previous
|
||||
[examples](guide/form-validation#reactive-component-class) in
|
||||
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" header="shared/forbidden-name.directive.ts (forbiddenNameValidator)" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="custom-validator" header="shared/forbidden-name.directive.ts (forbiddenNameValidator)"></code-example>
|
||||
|
||||
The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name and returns a validator function.
|
||||
|
||||
@@ -148,8 +143,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
|
||||
to the `FormControl`.
|
||||
|
||||
<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 path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="custom-validator" header="reactive/hero-form-reactive.component.ts (validator functions)"></code-example>
|
||||
|
||||
### Adding to template-driven forms
|
||||
|
||||
@@ -161,8 +155,7 @@ The corresponding `ForbiddenValidatorDirective` serves as a wrapper around the `
|
||||
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.
|
||||
|
||||
<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 path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive-providers" header="shared/forbidden-name.directive.ts (providers)"></code-example>
|
||||
|
||||
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
|
||||
@@ -173,9 +166,7 @@ comes together:
|
||||
|
||||
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" header="template/hero-form-template.component.html (forbidden-name-input)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<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)"></code-example>
|
||||
|
||||
|
||||
<div class="alert is-helpful">
|
||||
@@ -245,8 +236,7 @@ const heroForm = new FormGroup({
|
||||
|
||||
The validator code is as follows:
|
||||
|
||||
<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 path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-validator" header="shared/identity-revealed.directive.ts"></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.
|
||||
|
||||
@@ -255,8 +245,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.
|
||||
|
||||
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" header="reactive/hero-form-template.component.html" linenums="false">
|
||||
</code-example>
|
||||
<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"></code-example>
|
||||
|
||||
Note that we check if:
|
||||
- the `FormGroup` has the cross validation error returned by the `identityRevealed` validator,
|
||||
@@ -265,16 +254,13 @@ Note that we check if:
|
||||
### 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" header="shared/identity-revealed.directive.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-directive" header="shared/identity-revealed.directive.ts"></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.
|
||||
<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 path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-register-validator" header="template/hero-form-template.component.html"></code-example>
|
||||
|
||||
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" header="template/hero-form-template.component.html" linenums="false">
|
||||
</code-example>
|
||||
<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"></code-example>
|
||||
|
||||
Note that we check if:
|
||||
- the form has the cross validation error returned by the `identityRevealed` validator,
|
||||
@@ -313,7 +299,7 @@ To validate the potential alter ego, we need to consult a central database of al
|
||||
|
||||
Let's start by creating the validator class.
|
||||
|
||||
<code-example path="form-validation/src/app/shared/alter-ego.directive.ts" region="async-validator" linenums="false"></code-example>
|
||||
<code-example path="form-validation/src/app/shared/alter-ego.directive.ts" region="async-validator"></code-example>
|
||||
|
||||
As you can see, the `UniqueAlterEgoValidator` class implements the `AsyncValidator` interface. In the constructor, we inject the `HeroesService` that has the following interface:
|
||||
|
||||
|
||||
+24
-72
@@ -109,9 +109,7 @@ Using the Angular CLI command [`ng generate class`](cli/generate), generate a ne
|
||||
|
||||
With this content:
|
||||
|
||||
<code-example path="forms/src/app/hero.ts" header="src/app/hero.ts">
|
||||
|
||||
</code-example>
|
||||
<code-example path="forms/src/app/hero.ts" header="src/app/hero.ts"></code-example>
|
||||
|
||||
It's an anemic model with few requirements and no behavior. Perfect for the demo.
|
||||
|
||||
@@ -122,9 +120,7 @@ The `alterEgo` is optional, so the constructor lets you omit it; note the questi
|
||||
|
||||
You can create a new hero like this:
|
||||
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" region="SkyDog">
|
||||
|
||||
</code-example>
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.ts" region="SkyDog"></code-example>
|
||||
|
||||
## Create a form component
|
||||
|
||||
@@ -142,9 +138,7 @@ Using the Angular CLI command [`ng generate component`](cli/generate), generate
|
||||
|
||||
With this content:
|
||||
|
||||
<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 path="forms/src/app/hero-form/hero-form.component.ts" header="src/app/hero-form/hero-form.component.ts (v1)" region="v1"></code-example>
|
||||
|
||||
There’s nothing special about this component, nothing form-specific,
|
||||
nothing to distinguish it from any component you've written before.
|
||||
@@ -176,9 +170,7 @@ Because template-driven forms are in their own module, you need to add the `Form
|
||||
|
||||
Update it with the following:
|
||||
|
||||
<code-example path="forms/src/app/app.module.ts" header="src/app/app.module.ts">
|
||||
|
||||
</code-example>
|
||||
<code-example path="forms/src/app/app.module.ts" header="src/app/app.module.ts"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@@ -204,9 +196,7 @@ Update it with the following:
|
||||
|
||||
Replace the contents of its template with the following:
|
||||
|
||||
<code-example path="forms/src/app/app.component.html" header="src/app/app.component.html">
|
||||
|
||||
</code-example>
|
||||
<code-example path="forms/src/app/app.component.html" header="src/app/app.component.html"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@@ -221,9 +211,7 @@ Replace the contents of its template with the following:
|
||||
|
||||
Update the template file with the following contents:
|
||||
|
||||
<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 path="forms/src/app/hero-form/hero-form.component.html" region="start" header="src/app/hero-form/hero-form.component.html"></code-example>
|
||||
|
||||
The language is simply HTML5. You're presenting two of the `Hero` fields, `name` and `alterEgo`, and
|
||||
opening them up for user input in input boxes.
|
||||
@@ -259,9 +247,7 @@ Bootstrap gives the form a little style.
|
||||
|
||||
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" header="src/styles.css">
|
||||
|
||||
</code-example>
|
||||
<code-example path="forms/src/styles.1.css" header="src/styles.css"></code-example>
|
||||
|
||||
## Add powers with _*ngFor_
|
||||
|
||||
@@ -274,9 +260,7 @@ a technique seen previously in the [Displaying Data](guide/displaying-data) page
|
||||
|
||||
Add the following HTML *immediately below* the *Alter Ego* group:
|
||||
|
||||
<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 path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (powers)" region="powers"></code-example>
|
||||
|
||||
This code repeats the `<option>` tag for each power in the list of powers.
|
||||
The `pow` template input variable is a different power in each iteration;
|
||||
@@ -307,9 +291,7 @@ makes binding the form to the model easy.
|
||||
|
||||
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" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-1">
|
||||
|
||||
</code-example>
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-1"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@@ -325,9 +307,7 @@ You need one more addition to display the data. Declare
|
||||
a template variable for the form. Update the `<form>` tag with
|
||||
`#heroForm="ngForm"` as follows:
|
||||
|
||||
<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 path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="template-variable"></code-example>
|
||||
|
||||
The variable `heroForm` is now a reference to the `NgForm` directive that governs the form as a whole.
|
||||
|
||||
@@ -391,9 +371,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:
|
||||
|
||||
<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 path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModel-2"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@@ -493,9 +471,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`
|
||||
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" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-2">
|
||||
|
||||
</code-example>
|
||||
<code-example path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-2"></code-example>
|
||||
|
||||
Now run the app and look at the _Name_ input box.
|
||||
Follow these steps *precisely*:
|
||||
@@ -535,15 +511,11 @@ on the left of the input box:
|
||||
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`:
|
||||
|
||||
<code-example path="forms/src/assets/forms.css" header="src/assets/forms.css">
|
||||
|
||||
</code-example>
|
||||
<code-example path="forms/src/assets/forms.css" header="src/assets/forms.css"></code-example>
|
||||
|
||||
Update the `<head>` of `index.html` to include this style sheet:
|
||||
|
||||
<code-example path="forms/src/index.html" linenums="false" header="src/index.html (styles)" region="styles">
|
||||
|
||||
</code-example>
|
||||
<code-example path="forms/src/index.html" header="src/index.html (styles)" region="styles"></code-example>
|
||||
|
||||
## Show and hide validation error messages
|
||||
|
||||
@@ -564,9 +536,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:
|
||||
|
||||
<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 path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="name-with-error-msg"></code-example>
|
||||
|
||||
You need a template reference variable to access the input box's Angular control from within the template.
|
||||
Here you created a variable called `name` and gave it the value "ngModel".
|
||||
@@ -583,9 +553,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`
|
||||
control to the message `<div>` element's `hidden` property.
|
||||
|
||||
<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 path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (hidden-error-msg)" region="hidden-error-msg"></code-example>
|
||||
|
||||
In this example, you hide the message when the control is valid or pristine;
|
||||
"pristine" means the user hasn't changed the value since it was displayed in this form.
|
||||
@@ -609,13 +577,9 @@ power to valid values.
|
||||
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.
|
||||
|
||||
<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 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" header="src/app/hero-form/hero-form.component.ts (New Hero method)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<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)"></code-example>
|
||||
|
||||
Run the application again, click the *New Hero* button, and the form clears.
|
||||
The *required* bars to the left of the input box are red, indicating invalid `name` and `power` properties.
|
||||
@@ -634,9 +598,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
|
||||
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" header="src/app/hero-form/hero-form.component.html (Reset the form)">
|
||||
|
||||
</code-example>
|
||||
<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>
|
||||
|
||||
Now clicking "New Hero" resets both the form and its control flags.
|
||||
|
||||
@@ -651,9 +613,7 @@ A "form submit" is useless at the moment.
|
||||
To make it useful, bind the form's `ngSubmit` event property
|
||||
to the hero form component's `onSubmit()` method:
|
||||
|
||||
<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 path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (ngSubmit)" region="ngSubmit"></code-example>
|
||||
|
||||
You'd already defined a template reference variable,
|
||||
`#heroForm`, and initialized it with the value "ngForm".
|
||||
@@ -664,9 +624,7 @@ You'll bind the form's overall validity via
|
||||
the `heroForm` variable to the button's `disabled` property
|
||||
using an event binding. Here's the code:
|
||||
|
||||
<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 path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (submit-button)" region="submit-button"></code-example>
|
||||
|
||||
If you run the application now, you find that the button is enabled—although
|
||||
it doesn't do anything useful yet.
|
||||
@@ -703,17 +661,13 @@ hide the data entry area and display something else.
|
||||
Wrap the form in a `<div>` and bind
|
||||
its `hidden` property to the `HeroFormComponent.submitted` property.
|
||||
|
||||
<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 path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="edit-div"></code-example>
|
||||
|
||||
The main form is visible from the start because the
|
||||
`submitted` property is false until you submit the form,
|
||||
as this fragment from the `HeroFormComponent` shows:
|
||||
|
||||
<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 path="forms/src/app/hero-form/hero-form.component.ts" header="src/app/hero-form/hero-form.component.ts (submitted)" region="submitted"></code-example>
|
||||
|
||||
When you click the *Submit* button, the `submitted` flag becomes true and the form disappears
|
||||
as planned.
|
||||
@@ -721,9 +675,7 @@ as planned.
|
||||
Now the app needs to show something else while the form is in the submitted state.
|
||||
Add the following HTML below the `<div>` wrapper you just wrote:
|
||||
|
||||
<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 path="forms/src/app/hero-form/hero-form.component.html" header="src/app/hero-form/hero-form.component.html (excerpt)" region="submitted"></code-example>
|
||||
|
||||
There's the hero again, displayed read-only with interpolation bindings.
|
||||
This `<div>` appears only while the component is in the submitted state.
|
||||
|
||||
@@ -763,7 +763,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.
|
||||
|
||||
<code-example path="architecture/src/app/app.component.ts" linenums="false" header="architecture/src/app/app.component.ts (import)" region="import">
|
||||
<code-example path="architecture/src/app/app.component.ts" header="architecture/src/app/app.component.ts (import)" region="import">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ an NgModule, directive-level injectors follow the structure of the component hie
|
||||
|
||||
The choices you make about where to configure providers lead to differences in the final bundle size, service _scope_, and service _lifetime_.
|
||||
|
||||
When you specify providers in the `@Injectable()` decorator of the service itself (typically at the app root level), optimization tools such as those used by the CLI's production builds can perform *tree shaking*, which removes services that aren't used by your app. Tree shaking results in smaller bundle sizes.
|
||||
When you specify providers in the `@Injectable()` decorator of the service itself (typically at the app root level), optimization tools such as those used by the CLI's production builds can perform *tree shaking*, which removes services that aren't used by your app. Tree shaking results in smaller bundle sizes.
|
||||
|
||||
* Learn more about [tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers).
|
||||
|
||||
@@ -29,12 +29,12 @@ You're likely to inject `UserService` in many places throughout the app and will
|
||||
<header>Platform injector</header>
|
||||
|
||||
When you use `providedIn:'root'`, you are configuring the root injector for the _app_, which is the injector for `AppModule`.
|
||||
The actual root of the entire injector hierarchy is a _platform injector_ that is the parent of app-root injectors.
|
||||
The actual root of the entire injector hierarchy is a _platform injector_ that is the parent of app-root injectors.
|
||||
This allows multiple apps to share a platform configuration. For example, a browser has only one URL bar, no matter how many apps you have running.
|
||||
|
||||
The platform injector is used internally during bootstrap, to configure platform-specific dependencies. You can configure additional platform-specific providers at the platform level by supplying `extraProviders` using the `platformBrowser()` function.
|
||||
The platform injector is used internally during bootstrap, to configure platform-specific dependencies. You can configure additional platform-specific providers at the platform level by supplying `extraProviders` using the `platformBrowser()` function.
|
||||
|
||||
Learn more about dependency resolution through the injector hierarchy:
|
||||
Learn more about dependency resolution through the injector hierarchy:
|
||||
[What you always wanted to know about Angular Dependency Injection tree](https://blog.angularindepth.com/angular-dependency-injection-and-tree-shakeable-tokens-4588a8f70d5d)
|
||||
|
||||
|
||||
@@ -42,24 +42,24 @@ Learn more about dependency resolution through the injector hierarchy:
|
||||
|
||||
*NgModule-level* providers can be specified with `@NgModule()` `providers` metadata option, or in the `@Injectable()` `providedIn` option (with some module other than the root `AppModule`).
|
||||
|
||||
Use the `@NgModule()` `providers` option if a module is [lazy loaded](guide/lazy-loading-ngmodules). The module's own injector is configured with the provider when that module is loaded, and Angular can inject the corresponding services in any class it creates in that module. If you use the `@Injectable()` option `providedIn: MyLazyloadModule`, the provider could be shaken out at compile time, if it is not used anywhere else in the app.
|
||||
Use the `@NgModule()` `providers` option if a module is [lazy loaded](guide/lazy-loading-ngmodules). The module's own injector is configured with the provider when that module is loaded, and Angular can inject the corresponding services in any class it creates in that module. If you use the `@Injectable()` option `providedIn: MyLazyloadModule`, the provider could be shaken out at compile time, if it is not used anywhere else in the app.
|
||||
|
||||
* Learn more about [tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers).
|
||||
|
||||
For both root-level and module-level injectors, a service instance lives for the life of the app or module, and Angular injects this one service instance in every class that needs it.
|
||||
|
||||
*Component-level* providers configure each component instance's own injector.
|
||||
Angular can only inject the corresponding services in that component instance or one of its descendant component instances.
|
||||
Angular can't inject the same service instance anywhere else.
|
||||
*Component-level* providers configure each component instance's own injector.
|
||||
Angular can only inject the corresponding services in that component instance or one of its descendant component instances.
|
||||
Angular can't inject the same service instance anywhere else.
|
||||
|
||||
A component-provided service may have a limited lifetime.
|
||||
Each new instance of the component gets its own instance of the service.
|
||||
A component-provided service may have a limited lifetime.
|
||||
Each new instance of the component gets its own instance of the service.
|
||||
When the component instance is destroyed, so is that service instance.
|
||||
|
||||
In our sample app, `HeroComponent` is created when the application starts
|
||||
In our sample app, `HeroComponent` is created when the application starts
|
||||
and is never destroyed,
|
||||
so the `HeroService` instance created for `HeroComponent` lives for the life of the app.
|
||||
If you want to restrict `HeroService` access to `HeroComponent` and its nested
|
||||
so the `HeroService` instance created for `HeroComponent` lives for the life of the app.
|
||||
If you want to restrict `HeroService` access to `HeroComponent` and its nested
|
||||
`HeroListComponent`, provide `HeroService` at the component level, in `HeroComponent` metadata.
|
||||
|
||||
* See more [examples of component-level injection](#component-injectors) below.
|
||||
@@ -67,32 +67,32 @@ If you want to restrict `HeroService` access to `HeroComponent` and its nested
|
||||
|
||||
{@a register-providers-injectable}
|
||||
|
||||
### @Injectable-level configuration
|
||||
### @Injectable-level configuration
|
||||
|
||||
The `@Injectable()` decorator identifies every service class. The `providedIn` metadata option for a service class configures a specific injector (typically `root`)
|
||||
to use the decorated class as a provider of the service.
|
||||
When an injectable class provides its own service to the `root` injector, the service is available anywhere the class is imported.
|
||||
to use the decorated class as a provider of the service.
|
||||
When an injectable class provides its own service to the `root` injector, the service is available anywhere the class is imported.
|
||||
|
||||
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" header="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"></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,
|
||||
and for making that instance available across the application.
|
||||
and for making that instance available across the application.
|
||||
|
||||
Providing a service with the app's root injector is a typical case,
|
||||
and the CLI sets up this kind of a provider automatically for you
|
||||
when generating a new service.
|
||||
when generating a new service.
|
||||
However, you might not always want to provide your service at the root level.
|
||||
You might, for instance, want users to explicitly opt-in to using the service.
|
||||
|
||||
Instead of specifying the `root` injector, you can set `providedIn` to a specific NgModule.
|
||||
Instead of specifying the `root` injector, you can set `providedIn` to a specific NgModule.
|
||||
|
||||
For example, in the following excerpt, the `@Injectable()` decorator configures a provider
|
||||
that is available in any injector that includes the `HeroModule`.
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.4.ts" header="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"></code-example>
|
||||
|
||||
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.
|
||||
@@ -108,18 +108,16 @@ and leave it up to the app whether to provide the service.
|
||||
You can configure a provider at the module level using the `providers` metadata option for a non-root NgModule, in order to limit the scope of the provider to that module.
|
||||
This is the equivalent of specifying the non-root module in the `@Injectable()` metadata, except that the service provided via `providers` is not tree-shakable.
|
||||
|
||||
You generally don't need to specify `AppModule` with `providedIn`, because the app's `root` injector is the `AppModule` injector.
|
||||
You generally don't need to specify `AppModule` with `providedIn`, because the app's `root` injector is the `AppModule` injector.
|
||||
However, if you configure a app-wide provider in the `@NgModule()` metadata for `AppModule`,
|
||||
it overrides one configured for `root` in the `@Injectable()` metadata.
|
||||
You can do this to configure a non-default provider of a service that is shared with multiple apps.
|
||||
it overrides one configured for `root` in the `@Injectable()` metadata.
|
||||
You can do this to configure a non-default provider of a service that is shared with multiple apps.
|
||||
|
||||
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
|
||||
in the `providers` list of the `AppModule`.
|
||||
|
||||
<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 path="dependency-injection-in-action/src/app/app.module.ts" region="providers" header="src/app/app.module.ts (providers)"></code-example>
|
||||
|
||||
|
||||
{@a register-providers-component}
|
||||
@@ -130,19 +128,18 @@ Individual components within an NgModule have their own injectors.
|
||||
You can limit the scope of a provider to a component and its children
|
||||
by configuring the provider at the component level using the `@Component` metadata.
|
||||
|
||||
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" header="src/app/heroes/heroes.component.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts"></code-example>
|
||||
|
||||
### Element injectors
|
||||
|
||||
An injector does not actually belong to a component, but rather to the component instance's anchor element in the DOM. A different component instance on a different DOM element uses a different injector.
|
||||
|
||||
Components are a special type of directive, and the `providers` property of
|
||||
`@Component()` is inherited from `@Directive()`.
|
||||
`@Component()` is inherited from `@Directive()`.
|
||||
Directives can also have dependencies, and you can configure providers
|
||||
in their `@Directive()` metadata.
|
||||
in their `@Directive()` metadata.
|
||||
When you configure a provider for a component or directive using the `providers` property, that provider belongs to the injector for the anchor DOM element. Components and directives on the same element share an injector.
|
||||
|
||||
<!--- TBD with examples
|
||||
@@ -168,16 +165,16 @@ When a component requests a dependency, Angular tries to satisfy that dependency
|
||||
If the component's injector lacks the provider, it passes the request up to its parent component's injector.
|
||||
If that injector can't satisfy the request, it passes the request along to the next parent injector up the tree.
|
||||
The requests keep bubbling up until Angular finds an injector that can handle the request or runs out of ancestor injectors.
|
||||
If it runs out of ancestors, Angular throws an error.
|
||||
If it runs out of ancestors, Angular throws an error.
|
||||
|
||||
If you have registered a provider for the same DI token at different levels, the first one Angular encounters is the one it uses to provide the dependency. If, for example, a provider is registered locally in the component that needs a service, Angular doesn't look for another provider of the same service.
|
||||
If you have registered a provider for the same DI token at different levels, the first one Angular encounters is the one it uses to provide the dependency. If, for example, a provider is registered locally in the component that needs a service, Angular doesn't look for another provider of the same service.
|
||||
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
You can cap the bubbling by adding the `@Host()` parameter decorator on the dependant-service parameter
|
||||
in a component's constructor.
|
||||
The hunt for providers stops at the injector for the host element of the component.
|
||||
in a component's constructor.
|
||||
The hunt for providers stops at the injector for the host element of the component.
|
||||
|
||||
* See an [example](guide/dependency-injection-in-action#qualify-dependency-lookup) of using `@Host` together with `@Optional`, another parameter decorator that lets you handle the null case if no provider is found.
|
||||
|
||||
@@ -197,7 +194,7 @@ The guide sample offers some scenarios where you might want to do so.
|
||||
|
||||
### Scenario: service isolation
|
||||
|
||||
Architectural reasons may lead you to restrict access to a service to the application domain where it belongs.
|
||||
Architectural reasons may lead you to restrict access to a service to the application domain where it belongs.
|
||||
For example, the guide sample includes a `VillainsListComponent` that displays a list of villains.
|
||||
It gets those villains from a `VillainsService`.
|
||||
|
||||
@@ -207,9 +204,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:
|
||||
|
||||
|
||||
<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 path="hierarchical-dependency-injection/src/app/villains-list.component.ts" header="src/app/villains-list.component.ts (metadata)" region="metadata"></code-example>
|
||||
|
||||
By providing `VillainsService` in the `VillainsListComponent` metadata and nowhere else,
|
||||
the service becomes available only in the `VillainsListComponent` and its sub-component tree.
|
||||
@@ -273,9 +268,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.
|
||||
|
||||
|
||||
<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 path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" header="src/app/hero-tax-return.component.ts (providers)" region="providers"></code-example>
|
||||
|
||||
The `HeroTaxReturnComponent` has its own provider of the `HeroTaxReturnService`.
|
||||
Recall that every component _instance_ has its own injector.
|
||||
|
||||
+194
-201
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user