docs: minor fixes (anchor tags, redundant whitespace, consistent code-snippets lang) (#21589)
PR Close #21589
This commit is contained in:
parent
1ce46b56f8
commit
bf248792eb
|
@ -78,172 +78,172 @@ With no templates to read and no risky client-side HTML or JavaScript evaluation
|
||||||
there are fewer opportunities for injection attacks.
|
there are fewer opportunities for injection attacks.
|
||||||
|
|
||||||
{@a compiler-options}
|
{@a compiler-options}
|
||||||
|
|
||||||
## Angular Compiler Options
|
## Angular Compiler Options
|
||||||
|
|
||||||
You can control your app compilation by providing template compiler options in the `tsconfig.json` file along with the options supplied to the TypeScript compiler. The template compiler options are specified as members of
|
You can control your app compilation by providing template compiler options in the `tsconfig.json` file along with the options supplied to the TypeScript compiler. The template compiler options are specified as members of
|
||||||
`"angularCompilerOptions"` object as shown below:
|
`"angularCompilerOptions"` object as shown below:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
...
|
...
|
||||||
},
|
},
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"fullTemplateTypeCheck": true,
|
"fullTemplateTypeCheck": true,
|
||||||
"preserveWhiteSpace": false,
|
"preserveWhiteSpace": false,
|
||||||
...
|
...
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
}
|
||||||
|
```
|
||||||
### *skipMetadataEmit*
|
|
||||||
|
|
||||||
This option tells the compiler not to produce `.metadata.json` files.
|
### *skipMetadataEmit*
|
||||||
The option is `false` by default.
|
|
||||||
|
|
||||||
`.metadata.json` files contain infomration needed by the template compiler from a `.ts`
|
|
||||||
file that is not included in the `.d.ts` file produced by the TypeScript compiler. This information contains,
|
|
||||||
for example, the content of annotations (such as a component's template) which TypeScript
|
|
||||||
emits to the `.js` file but not to the `.d.ts` file.
|
|
||||||
|
|
||||||
This option should be set to `true` if using TypeScript's `--outFile` option, as the metadata files
|
|
||||||
are not valid for this style of TypeScript output. It is not recommeded to use `--outFile` with
|
|
||||||
Angular. Use a bundler, such as [webpack](https://webpack.js.org/), instead.
|
|
||||||
|
|
||||||
This option can also be set to `true` when using factory summaries as the factory summaries
|
|
||||||
include a copy of the information that is in the `.metadata.json` file.
|
|
||||||
|
|
||||||
### *strictMetadataEmit*
|
|
||||||
|
|
||||||
This option tells the template compiler to report an error to the `.metadata.json`
|
|
||||||
file if `"skipMetadataEmit"` is `false` . This option is `false` by default. This should only be used when `"skipMetadataEmit"` is `false` and `"skipTemplateCodeGen"` is `true`.
|
|
||||||
|
|
||||||
It is intended to validate the `.metadata.json` files emitted for bundling with an `npm` package. The validation is overly strict and can emit errors for metadata that would never produce an error when used by the template compiler. You can choose to suppress the error emitted by this option for an exported symbol by including `@dynamic` in the comment documenting the symbol.
|
|
||||||
|
|
||||||
It is valid for `.metadata.json` files to contain errors. The template compiler reports these errors
|
|
||||||
if the metadata is used to determine the contents of an annotation. The metadata
|
|
||||||
collector cannot predict the symbols that are designed to use in an annotation, so it will preemptively
|
|
||||||
include error nodes in the metadata for the exported symbols. The template compiler can then use the error
|
|
||||||
nodes to report an error if these symbols are used. If the client of a library intends to use a symbol in an annotation, the template compiler will not normally report
|
|
||||||
this until the client uses the symbol. This option allows detecting these errors during the build phase of
|
|
||||||
the library and is used, for example, in producing Angular libraries themselves.
|
|
||||||
|
|
||||||
### *skipTemplateCodegen*
|
|
||||||
|
|
||||||
This option tells the compiler to suppress emitting `.ngfactory.js` and `.ngstyle.js` files. When set,
|
|
||||||
this turns off most of the template compiler and disables reporting template diagnostics.
|
|
||||||
This option can be used to instruct the
|
|
||||||
template compiler to produce `.metadata.json` files for distribution with an `npm` package while
|
|
||||||
avoiding the production of `.ngfactory.js` and `.ngstyle.js` files that cannot be distributed to
|
|
||||||
`npm`.
|
|
||||||
|
|
||||||
### *strictInjectionParameters*
|
|
||||||
|
|
||||||
When set to `true`, this options tells the compiler to report an error for a parameter supplied
|
|
||||||
whose injection type cannot be determined. When this value option is not provided or is `false`, constructor parameters of classes marked with `@Injectable` whose type cannot be resolved will
|
|
||||||
produce a warning.
|
|
||||||
|
|
||||||
*Note*: It is recommended to change this option explicitly to `true` as this option will default to `true` in the future.
|
This option tells the compiler not to produce `.metadata.json` files.
|
||||||
|
The option is `false` by default.
|
||||||
### *flatModuleOutFile*
|
|
||||||
|
`.metadata.json` files contain infomration needed by the template compiler from a `.ts`
|
||||||
When set to `true`, this option tells the template compiler to generate a flat module
|
file that is not included in the `.d.ts` file produced by the TypeScript compiler. This information contains,
|
||||||
index of the given file name and the corresponding flat module metadata. Use this option when creating
|
for example, the content of annotations (such as a component's template) which TypeScript
|
||||||
flat modules that are packaged similarly to `@angular/core` and `@angular/common`. When this option
|
emits to the `.js` file but not to the `.d.ts` file.
|
||||||
is used, the `package.json` for the library should refer
|
|
||||||
to the generated flat module index instead of the library index file. With this
|
This option should be set to `true` if using TypeScript's `--outFile` option, as the metadata files
|
||||||
option only one `.metadata.json` file is produced that contains all the metadata necessary
|
are not valid for this style of TypeScript output. It is not recommeded to use `--outFile` with
|
||||||
for symbols exported from the library index. In the generated `.ngfactory.js` files, the flat
|
Angular. Use a bundler, such as [webpack](https://webpack.js.org/), instead.
|
||||||
module index is used to import symbols that includes both the public API from the library index
|
|
||||||
as well as shrowded internal symbols.
|
This option can also be set to `true` when using factory summaries as the factory summaries
|
||||||
|
include a copy of the information that is in the `.metadata.json` file.
|
||||||
By default the `.ts` file supplied in the `files` field is assumed to be library index.
|
|
||||||
If more than one `.ts` file is specified, `libraryIndex` is used to select the file to use.
|
### *strictMetadataEmit*
|
||||||
If more than one `.ts` file is supplied without a `libraryIndex`, an error is produced. A flat module
|
|
||||||
index `.d.ts` and `.js` will be created with the given `flatModuleOutFile` name in the same
|
This option tells the template compiler to report an error to the `.metadata.json`
|
||||||
location as the library index `.d.ts` file. For example, if a library uses
|
file if `"skipMetadataEmit"` is `false` . This option is `false` by default. This should only be used when `"skipMetadataEmit"` is `false` and `"skipTemplateCodeGen"` is `true`.
|
||||||
`public_api.ts` file as the library index of the module, the `tsconfig.json` `files` field
|
|
||||||
would be `["public_api.ts"]`. The `flatModuleOutFile` options could then be set to, for
|
It is intended to validate the `.metadata.json` files emitted for bundling with an `npm` package. The validation is overly strict and can emit errors for metadata that would never produce an error when used by the template compiler. You can choose to suppress the error emitted by this option for an exported symbol by including `@dynamic` in the comment documenting the symbol.
|
||||||
example `"index.js"`, which produces `index.d.ts` and `index.metadata.json` files. The
|
|
||||||
library's `package.json`'s `module` field would be `"index.js"` and the `typings` field
|
It is valid for `.metadata.json` files to contain errors. The template compiler reports these errors
|
||||||
would be `"index.d.ts"`.
|
if the metadata is used to determine the contents of an annotation. The metadata
|
||||||
|
collector cannot predict the symbols that are designed to use in an annotation, so it will preemptively
|
||||||
### *flatModuleId*
|
include error nodes in the metadata for the exported symbols. The template compiler can then use the error
|
||||||
|
nodes to report an error if these symbols are used. If the client of a library intends to use a symbol in an annotation, the template compiler will not normally report
|
||||||
This option specifies the preferred module id to use for importing a flat module.
|
this until the client uses the symbol. This option allows detecting these errors during the build phase of
|
||||||
References generated by the template compiler will use this module name when importing symbols
|
the library and is used, for example, in producing Angular libraries themselves.
|
||||||
from the flat module.
|
|
||||||
This is only meaningful when `flatModuleOutFile` is also supplied. Otherwise the compiler ignores
|
### *skipTemplateCodegen*
|
||||||
this option.
|
|
||||||
|
This option tells the compiler to suppress emitting `.ngfactory.js` and `.ngstyle.js` files. When set,
|
||||||
### *generateCodeForLibraries*
|
this turns off most of the template compiler and disables reporting template diagnostics.
|
||||||
|
This option can be used to instruct the
|
||||||
This option tells the template compiler to generate factory files (`.ngfactory.js` and `.ngstyle.js`)
|
template compiler to produce `.metadata.json` files for distribution with an `npm` package while
|
||||||
for `.d.ts` files with a corresponding `.metadata.json` file. This option defaults to
|
avoiding the production of `.ngfactory.js` and `.ngstyle.js` files that cannot be distributed to
|
||||||
`true`. When this option is `false`, factory files are generated only for `.ts` files.
|
`npm`.
|
||||||
|
|
||||||
This option should be set to `false` when using factory summaries.
|
### *strictInjectionParameters*
|
||||||
|
|
||||||
### *fullTemplateTypeCheck*
|
When set to `true`, this options tells the compiler to report an error for a parameter supplied
|
||||||
|
whose injection type cannot be determined. When this value option is not provided or is `false`, constructor parameters of classes marked with `@Injectable` whose type cannot be resolved will
|
||||||
This option tells the compiler to enable the [binding expression validation](#binding-expresion-validation)
|
produce a warning.
|
||||||
phase of the template compiler which uses TypeScript to validate binding expressions.
|
|
||||||
|
*Note*: It is recommended to change this option explicitly to `true` as this option will default to `true` in the future.
|
||||||
This option is `false` by default.
|
|
||||||
|
### *flatModuleOutFile*
|
||||||
*Note*: It is recommended to set this to `true` as this option will default to `true` in the future.
|
|
||||||
|
When set to `true`, this option tells the template compiler to generate a flat module
|
||||||
### *annotateForClosureCompiler*
|
index of the given file name and the corresponding flat module metadata. Use this option when creating
|
||||||
|
flat modules that are packaged similarly to `@angular/core` and `@angular/common`. When this option
|
||||||
This option tells the compiler to use [Tsickle](https://github.com/angular/tsickle) to annotate the emitted
|
is used, the `package.json` for the library should refer
|
||||||
JavaScript with [JsDoc](http://usejsdoc.org/) comments needed by the
|
to the generated flat module index instead of the library index file. With this
|
||||||
[Closure Compiler](https://github.com/google/closure-compiler). This option defaults to `false`.
|
option only one `.metadata.json` file is produced that contains all the metadata necessary
|
||||||
|
for symbols exported from the library index. In the generated `.ngfactory.js` files, the flat
|
||||||
### *annotationsAs*
|
module index is used to import symbols that includes both the public API from the library index
|
||||||
|
as well as shrowded internal symbols.
|
||||||
Use this option to modify how the Angular specific annotations are emitted to improve tree-shaking. Non-Angular
|
|
||||||
annotations and decorators are unnaffected. Default is `static fields`.
|
By default the `.ts` file supplied in the `files` field is assumed to be library index.
|
||||||
|
If more than one `.ts` file is specified, `libraryIndex` is used to select the file to use.
|
||||||
value | description
|
If more than one `.ts` file is supplied without a `libraryIndex`, an error is produced. A flat module
|
||||||
----------------|-------------------------------------------------------------
|
index `.d.ts` and `.js` will be created with the given `flatModuleOutFile` name in the same
|
||||||
`decorators` | Leave the Decorators in-place. This makes compilation faster. TypeScript will emit calls to the __decorate helper. Use `--emitDecoratorMetadata` for runtime reflection. However, the resulting code will not properly tree-shake.
|
location as the library index `.d.ts` file. For example, if a library uses
|
||||||
`static fields` | Replace decorators with a static field in the class. Allows advanced tree-shakers like [Closure Compiler](https://github.com/google/closure-compiler) to remove unused classes.
|
`public_api.ts` file as the library index of the module, the `tsconfig.json` `files` field
|
||||||
|
would be `["public_api.ts"]`. The `flatModuleOutFile` options could then be set to, for
|
||||||
### *trace*
|
example `"index.js"`, which produces `index.d.ts` and `index.metadata.json` files. The
|
||||||
|
library's `package.json`'s `module` field would be `"index.js"` and the `typings` field
|
||||||
This tells the compiler to print extra information while compiling templates.
|
would be `"index.d.ts"`.
|
||||||
|
|
||||||
### *enableLegacyTemplate*
|
### *flatModuleId*
|
||||||
|
|
||||||
The use of `<template>` element was deprecated starting in Angular 4.0 in favor of using
|
This option specifies the preferred module id to use for importing a flat module.
|
||||||
`<ng-template>` to avoid colliding with the DOM's element of the same name. Setting this option to
|
References generated by the template compiler will use this module name when importing symbols
|
||||||
`true` enables the use of the deprecated `<template>` element . This option
|
from the flat module.
|
||||||
is `false` by default. This option might be required by some third-party Angular libraries.
|
This is only meaningful when `flatModuleOutFile` is also supplied. Otherwise the compiler ignores
|
||||||
|
this option.
|
||||||
### *disableExpressionLowering*
|
|
||||||
|
### *generateCodeForLibraries*
|
||||||
The Angular template compiler transforms code that is used, or could be used, in an annotation
|
|
||||||
to allow it to be imported from template factory modules. See
|
This option tells the template compiler to generate factory files (`.ngfactory.js` and `.ngstyle.js`)
|
||||||
[metadata rewriting](#metadata-rewriting) for more information.
|
for `.d.ts` files with a corresponding `.metadata.json` file. This option defaults to
|
||||||
|
`true`. When this option is `false`, factory files are generated only for `.ts` files.
|
||||||
Setting this option to `false` disables this rewriting, requiring the rewriting to be
|
|
||||||
done manually.
|
This option should be set to `false` when using factory summaries.
|
||||||
|
|
||||||
### *preserveWhitespaces*
|
### *fullTemplateTypeCheck*
|
||||||
|
|
||||||
This option tells the compiler whether to remove blank text nodes from compiled templates.
|
This option tells the compiler to enable the [binding expression validation](#binding-expresion-validation)
|
||||||
This option is `true` by default.
|
phase of the template compiler which uses TypeScript to validate binding expressions.
|
||||||
|
|
||||||
*Note*: It is recommended to set this explicitly to `false` as it emits smaller template factory modules and might be set to `false` by default in the future.
|
This option is `false` by default.
|
||||||
|
|
||||||
### *allowEmptyCodegenFiles*
|
*Note*: It is recommended to set this to `true` as this option will default to `true` in the future.
|
||||||
|
|
||||||
Tells the compiler to generate all the possible generated files even if they are empty. This option is
|
### *annotateForClosureCompiler*
|
||||||
`false` by default. This is an option used by `bazel` build rules and is needed to simplify
|
|
||||||
how `bazel` rules track file dependencies. It is not recommended to use this option outside of the `bazel`
|
This option tells the compiler to use [Tsickle](https://github.com/angular/tsickle) to annotate the emitted
|
||||||
rules.
|
JavaScript with [JsDoc](http://usejsdoc.org/) comments needed by the
|
||||||
|
[Closure Compiler](https://github.com/google/closure-compiler). This option defaults to `false`.
|
||||||
|
|
||||||
|
### *annotationsAs*
|
||||||
|
|
||||||
|
Use this option to modify how the Angular specific annotations are emitted to improve tree-shaking. Non-Angular
|
||||||
|
annotations and decorators are unnaffected. Default is `static fields`.
|
||||||
|
|
||||||
|
value | description
|
||||||
|
----------------|-------------------------------------------------------------
|
||||||
|
`decorators` | Leave the Decorators in-place. This makes compilation faster. TypeScript will emit calls to the __decorate helper. Use `--emitDecoratorMetadata` for runtime reflection. However, the resulting code will not properly tree-shake.
|
||||||
|
`static fields` | Replace decorators with a static field in the class. Allows advanced tree-shakers like [Closure Compiler](https://github.com/google/closure-compiler) to remove unused classes.
|
||||||
|
|
||||||
|
### *trace*
|
||||||
|
|
||||||
|
This tells the compiler to print extra information while compiling templates.
|
||||||
|
|
||||||
|
### *enableLegacyTemplate*
|
||||||
|
|
||||||
|
The use of `<template>` element was deprecated starting in Angular 4.0 in favor of using
|
||||||
|
`<ng-template>` to avoid colliding with the DOM's element of the same name. Setting this option to
|
||||||
|
`true` enables the use of the deprecated `<template>` element . This option
|
||||||
|
is `false` by default. This option might be required by some third-party Angular libraries.
|
||||||
|
|
||||||
|
### *disableExpressionLowering*
|
||||||
|
|
||||||
|
The Angular template compiler transforms code that is used, or could be used, in an annotation
|
||||||
|
to allow it to be imported from template factory modules. See
|
||||||
|
[metadata rewriting](#metadata-rewriting) for more information.
|
||||||
|
|
||||||
|
Setting this option to `false` disables this rewriting, requiring the rewriting to be
|
||||||
|
done manually.
|
||||||
|
|
||||||
|
### *preserveWhitespaces*
|
||||||
|
|
||||||
|
This option tells the compiler whether to remove blank text nodes from compiled templates.
|
||||||
|
This option is `true` by default.
|
||||||
|
|
||||||
|
*Note*: It is recommended to set this explicitly to `false` as it emits smaller template factory modules and might be set to `false` by default in the future.
|
||||||
|
|
||||||
|
### *allowEmptyCodegenFiles*
|
||||||
|
|
||||||
|
Tells the compiler to generate all the possible generated files even if they are empty. This option is
|
||||||
|
`false` by default. This is an option used by `bazel` build rules and is needed to simplify
|
||||||
|
how `bazel` rules track file dependencies. It is not recommended to use this option outside of the `bazel`
|
||||||
|
rules.
|
||||||
|
|
||||||
## Angular Metadata and AOT
|
## Angular Metadata and AOT
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ and [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Re
|
||||||
|
|
||||||
Consider the following component decorator:
|
Consider the following component decorator:
|
||||||
|
|
||||||
```ts
|
```typescript
|
||||||
@Component({
|
@Component({
|
||||||
...
|
...
|
||||||
providers: [{provide: server, useFactory: () => new Server()}]
|
providers: [{provide: server, useFactory: () => new Server()}]
|
||||||
|
@ -367,7 +367,7 @@ When the compiler later interprets this node, it reports an error that invites y
|
||||||
|
|
||||||
You can fix the error by converting to this:
|
You can fix the error by converting to this:
|
||||||
|
|
||||||
```ts
|
```typescript
|
||||||
export function serverFactory() {
|
export function serverFactory() {
|
||||||
return new Server();
|
return new Server();
|
||||||
}
|
}
|
||||||
|
@ -406,7 +406,7 @@ module-local `const` declarations and initialized `var` and `let` declarations,
|
||||||
|
|
||||||
Consider the following component definition:
|
Consider the following component definition:
|
||||||
|
|
||||||
```ts
|
```typescript
|
||||||
const template = '<div>{{hero.name}}</div>';
|
const template = '<div>{{hero.name}}</div>';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -423,7 +423,7 @@ The compiler could not refer to the `template` constant because it isn't exporte
|
||||||
But the _collector_ can _fold_ the `template` constant into the metadata definition by inlining its contents.
|
But the _collector_ can _fold_ the `template` constant into the metadata definition by inlining its contents.
|
||||||
The effect is the same as if you had written:
|
The effect is the same as if you had written:
|
||||||
|
|
||||||
```TypeScript
|
```typescript
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hero',
|
selector: 'app-hero',
|
||||||
template: '<div>{{hero.name}}</div>'
|
template: '<div>{{hero.name}}</div>'
|
||||||
|
@ -437,7 +437,7 @@ There is no longer a reference to `template` and, therefore, nothing to trouble
|
||||||
|
|
||||||
You can take this example a step further by including the `template` constant in another expression:
|
You can take this example a step further by including the `template` constant in another expression:
|
||||||
|
|
||||||
```TypeScript
|
```typescript
|
||||||
const template = '<div>{{hero.name}}</div>';
|
const template = '<div>{{hero.name}}</div>';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -495,7 +495,7 @@ Decorated component class members must be public. You cannot make an `@Input()`
|
||||||
|
|
||||||
Data bound properties must also be public.
|
Data bound properties must also be public.
|
||||||
|
|
||||||
```TypeScript
|
```typescript
|
||||||
// BAD CODE - title is private
|
// BAD CODE - title is private
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
|
@ -547,7 +547,7 @@ methods that return an expression.
|
||||||
|
|
||||||
For example, consider the following function:
|
For example, consider the following function:
|
||||||
|
|
||||||
```TypeScript
|
```typescript
|
||||||
export function wrapInArray<T>(value: T): T[] {
|
export function wrapInArray<T>(value: T): T[] {
|
||||||
return [value];
|
return [value];
|
||||||
}
|
}
|
||||||
|
@ -557,7 +557,7 @@ You can call the `wrapInArray` in a metadata definition because it returns the v
|
||||||
|
|
||||||
You might use `wrapInArray()` like this:
|
You might use `wrapInArray()` like this:
|
||||||
|
|
||||||
```TypeScript
|
```typescript
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: wrapInArray(TypicalComponent)
|
declarations: wrapInArray(TypicalComponent)
|
||||||
})
|
})
|
||||||
|
@ -566,7 +566,7 @@ export class TypicalModule {}
|
||||||
|
|
||||||
The compiler treats this usage as if you had written:
|
The compiler treats this usage as if you had written:
|
||||||
|
|
||||||
```TypeScript
|
```typescript
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [TypicalComponent]
|
declarations: [TypicalComponent]
|
||||||
})
|
})
|
||||||
|
@ -580,7 +580,8 @@ The Angular [`RouterModule`](api/router/RouterModule) exports two macro static m
|
||||||
Review the [source code](https://github.com/angular/angular/blob/master/packages/router/src/router_module.ts#L139 "RouterModule.forRoot source code")
|
Review the [source code](https://github.com/angular/angular/blob/master/packages/router/src/router_module.ts#L139 "RouterModule.forRoot source code")
|
||||||
for these methods to see how macros can simplify configuration of complex [NgModules](guide/ngmodules).
|
for these methods to see how macros can simplify configuration of complex [NgModules](guide/ngmodules).
|
||||||
|
|
||||||
{@ metadata-rewriting}
|
{@a metadata-rewriting}
|
||||||
|
|
||||||
### Metadata rewriting
|
### Metadata rewriting
|
||||||
|
|
||||||
The compiler treats object literals containing the fields `useClass`, `useValue`, `useFactory`, and `data` specially. The compiler converts the expression initializing one of these fields into an exported variable, which replaces the expression. This process of rewriting these expressions removes all the restrictions on what can be in them because
|
The compiler treats object literals containing the fields `useClass`, `useValue`, `useFactory`, and `data` specially. The compiler converts the expression initializing one of these fields into an exported variable, which replaces the expression. This process of rewriting these expressions removes all the restrictions on what can be in them because
|
||||||
|
@ -590,7 +591,7 @@ the compiler doesn't need to know the expression's value—it just needs to
|
||||||
|
|
||||||
You might write something like:
|
You might write something like:
|
||||||
|
|
||||||
```ts
|
```typescript
|
||||||
class TypicalServer {
|
class TypicalServer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -605,7 +606,7 @@ Without rewriting, this would be invalid because lambdas are not supported and `
|
||||||
|
|
||||||
To allow this, the compiler automatically rewrites this to something like:
|
To allow this, the compiler automatically rewrites this to something like:
|
||||||
|
|
||||||
```ts
|
```typescript
|
||||||
class TypicalServer {
|
class TypicalServer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1132,21 +1133,21 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
|
||||||
|
|
||||||
-->
|
-->
|
||||||
{@a binding-expresion-validation}
|
{@a binding-expresion-validation}
|
||||||
|
|
||||||
## Phase 3: binding expression validation
|
## Phase 3: binding expression validation
|
||||||
|
|
||||||
In the validation phase, the Angular template compiler uses the TypeScript compiler to validate the
|
In the validation phase, the Angular template compiler uses the TypeScript compiler to validate the
|
||||||
binding expressions in templates. Enable this phase explicity by adding the compiler
|
binding expressions in templates. Enable this phase explicity by adding the compiler
|
||||||
option `"fullTemplateTypeCheck"` in the `"angularCompilerOptions"` of the project's `tsconfig.json` (see
|
option `"fullTemplateTypeCheck"` in the `"angularCompilerOptions"` of the project's `tsconfig.json` (see
|
||||||
[Angular Compiler Options](#compiler-options)).
|
[Angular Compiler Options](#compiler-options)).
|
||||||
|
|
||||||
Template validation produces error messages when a type error is detected in a template binding
|
Template validation produces error messages when a type error is detected in a template binding
|
||||||
expression, similar to how type errors are reported by the TypeScript compiler against code in a `.ts`
|
expression, similar to how type errors are reported by the TypeScript compiler against code in a `.ts`
|
||||||
file.
|
file.
|
||||||
|
|
||||||
For example, consider the following component:
|
For example, consider the following component:
|
||||||
|
|
||||||
```ts
|
```typescript
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-component',
|
selector: 'my-component',
|
||||||
template: '{{person.addresss.street}}'
|
template: '{{person.addresss.street}}'
|
||||||
|
@ -1155,35 +1156,35 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
|
||||||
person?: Person;
|
person?: Person;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This will produce the following error:
|
This will produce the following error:
|
||||||
|
|
||||||
```
|
```
|
||||||
my.component.ts.MyComponent.html(1,1): : Property 'addresss' does not exist on type 'Person'. Did you mean 'address'?
|
my.component.ts.MyComponent.html(1,1): : Property 'addresss' does not exist on type 'Person'. Did you mean 'address'?
|
||||||
```
|
```
|
||||||
|
|
||||||
The file name reported in the error message, `my.component.ts.MyComponent.html`, is a synthetic file
|
The file name reported in the error message, `my.component.ts.MyComponent.html`, is a synthetic file
|
||||||
generated by the template compiler that holds contents of the `MyComponent` class template.
|
generated by the template compiler that holds contents of the `MyComponent` class template.
|
||||||
Compiler never writes this file to disk. The line and column numbers are relative to the template string
|
Compiler never writes this file to disk. The line and column numbers are relative to the template string
|
||||||
in the `@Component` annotation of the class, `MyComponent` in this case. If a component uses
|
in the `@Component` annotation of the class, `MyComponent` in this case. If a component uses
|
||||||
`templateUrl` instead of `template`, the errors are reported in the HTML file refereneced by the
|
`templateUrl` instead of `template`, the errors are reported in the HTML file refereneced by the
|
||||||
`templateUrl` instead of a synthetic file.
|
`templateUrl` instead of a synthetic file.
|
||||||
|
|
||||||
The error location is the beginning of the text node that contains the interpolation expression with
|
The error location is the beginning of the text node that contains the interpolation expression with
|
||||||
the error. If the error is in an attribute binding such as `[value]="person.address.street"`, the error
|
the error. If the error is in an attribute binding such as `[value]="person.address.street"`, the error
|
||||||
location is the location of the attribute that contains the error.
|
location is the location of the attribute that contains the error.
|
||||||
|
|
||||||
The validation uses the TypeScript type checker and the options supplied to the TypeScript compiler to control
|
The validation uses the TypeScript type checker and the options supplied to the TypeScript compiler to control
|
||||||
how detailed the type validation is. For example, if the `strictTypeChecks` is specified, the error ```my.component.ts.MyComponent.html(1,1): : Object is possibly 'undefined'``` is reported as well as the above error message.
|
how detailed the type validation is. For example, if the `strictTypeChecks` is specified, the error ```my.component.ts.MyComponent.html(1,1): : Object is possibly 'undefined'``` is reported as well as the above error message.
|
||||||
|
|
||||||
### Type narrowing
|
### Type narrowing
|
||||||
|
|
||||||
The expression used in an `ngIf` directive is used to narrow type unions in the Angular
|
The expression used in an `ngIf` directive is used to narrow type unions in the Angular
|
||||||
template compiler, the same way the `if` expression does in TypeScript. For example, to avoid
|
template compiler, the same way the `if` expression does in TypeScript. For example, to avoid
|
||||||
`Object is possibly 'undefined'` error in the template above, modify it to only emit the
|
`Object is possibly 'undefined'` error in the template above, modify it to only emit the
|
||||||
interpolation if the value of `person` is initialized as shown below:
|
interpolation if the value of `person` is initialized as shown below:
|
||||||
|
|
||||||
```ts
|
```typescript
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-component',
|
selector: 'my-component',
|
||||||
template: '<span *ngIf="person"> {{person.addresss.street}} </span>'
|
template: '<span *ngIf="person"> {{person.addresss.street}} </span>'
|
||||||
|
@ -1192,38 +1193,38 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
|
||||||
person?: Person;
|
person?: Person;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Using `*ngIf` allows the TypeScript compiler to infer that the `person` used in the
|
Using `*ngIf` allows the TypeScript compiler to infer that the `person` used in the
|
||||||
binding expression will never be `undefined`.
|
binding expression will never be `undefined`.
|
||||||
|
|
||||||
#### Custom `ngIf` like directives
|
#### Custom `ngIf` like directives
|
||||||
|
|
||||||
Directives that behave like `*ngIf` can declare that they want the same treatment by including
|
Directives that behave like `*ngIf` can declare that they want the same treatment by including
|
||||||
a static member marker that is a signal to the template compiler to treat them
|
a static member marker that is a signal to the template compiler to treat them
|
||||||
like `*ngIf`. This static member for `*ngIf` is:
|
like `*ngIf`. This static member for `*ngIf` is:
|
||||||
|
|
||||||
```ts
|
```typescript
|
||||||
public static ngIfUseIfTypeGuard: void;
|
public static ngIfUseIfTypeGuard: void;
|
||||||
```
|
```
|
||||||
|
|
||||||
This declares that the input property `ngIf` of the `NgIf` directive should be treated as a
|
This declares that the input property `ngIf` of the `NgIf` directive should be treated as a
|
||||||
guard to the use of its template, implying that the template will only be instantiated if
|
guard to the use of its template, implying that the template will only be instantiated if
|
||||||
the `ngIf` input property is true.
|
the `ngIf` input property is true.
|
||||||
|
|
||||||
|
|
||||||
### Non-null type assertion operator
|
### Non-null type assertion operator
|
||||||
|
|
||||||
Use the [non-null type assertion operator](guide/template-syntax#non-null-assertion-operator)
|
Use the [non-null type assertion operator](guide/template-syntax#non-null-assertion-operator)
|
||||||
to suppress the `Object is possibly 'undefined'` error when it is incovienent to use
|
to suppress the `Object is possibly 'undefined'` error when it is incovienent to use
|
||||||
`*ngIf` or when some constraint in the component ensures that the expression is always
|
`*ngIf` or when some constraint in the component ensures that the expression is always
|
||||||
non-null when the binding expression is interpolated.
|
non-null when the binding expression is interpolated.
|
||||||
|
|
||||||
In the following example, the `person` and `address` properties are always set together,
|
In the following example, the `person` and `address` properties are always set together,
|
||||||
implying that `address` is always non-null if `person` is non-null. There is no convenient
|
implying that `address` is always non-null if `person` is non-null. There is no convenient
|
||||||
way to describe this constraint to TypeScript and the template compiler, but the error
|
way to describe this constraint to TypeScript and the template compiler, but the error
|
||||||
is suppressed in the example by using `address!.street`.
|
is suppressed in the example by using `address!.street`.
|
||||||
|
|
||||||
```ts
|
```typescript
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-component',
|
selector: 'my-component',
|
||||||
template: '<span *ngIf="person"> {{person.name}} lives on {{address!.street}} </span>'
|
template: '<span *ngIf="person"> {{person.name}} lives on {{address!.street}} </span>'
|
||||||
|
@ -1231,21 +1232,21 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
|
||||||
class MyComponent {
|
class MyComponent {
|
||||||
person?: Person;
|
person?: Person;
|
||||||
address?: Address;
|
address?: Address;
|
||||||
|
|
||||||
setData(person: Person, address: Address) {
|
setData(person: Person, address: Address) {
|
||||||
this.person = person;
|
this.person = person;
|
||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The non-null assertion operator should be used sparingly as refactoring of the component
|
The non-null assertion operator should be used sparingly as refactoring of the component
|
||||||
might break this constraint.
|
might break this constraint.
|
||||||
|
|
||||||
In this example it is recommended to include the checking of `address`
|
In this example it is recommended to include the checking of `address`
|
||||||
in the `*ngIf`as shown below:
|
in the `*ngIf`as shown below:
|
||||||
|
|
||||||
```ts
|
```typescript
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-component',
|
selector: 'my-component',
|
||||||
template: '<span *ngIf="person && address"> {{person.name}} lives on {{address.street}} </span>'
|
template: '<span *ngIf="person && address"> {{person.name}} lives on {{address.street}} </span>'
|
||||||
|
@ -1253,25 +1254,25 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
|
||||||
class MyComponent {
|
class MyComponent {
|
||||||
person?: Person;
|
person?: Person;
|
||||||
address?: Address;
|
address?: Address;
|
||||||
|
|
||||||
setData(person: Person, address: Address) {
|
setData(person: Person, address: Address) {
|
||||||
this.person = person;
|
this.person = person;
|
||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Disabling type checking using `$any()`
|
### Disabling type checking using `$any()`
|
||||||
|
|
||||||
Disable checking of a binding expression by surrounding the expression
|
Disable checking of a binding expression by surrounding the expression
|
||||||
in a call to the [`$any()` cast pseudo-function](guide/template-syntax).
|
in a call to the [`$any()` cast pseudo-function](guide/template-syntax).
|
||||||
The compiler treats it as a cast to the `any` type just like in TypeScript when a `<any>`
|
The compiler treats it as a cast to the `any` type just like in TypeScript when a `<any>`
|
||||||
or `as any` cast is used.
|
or `as any` cast is used.
|
||||||
|
|
||||||
In the following example, the error `Property addresss does not exist` is suppressed
|
In the following example, the error `Property addresss does not exist` is suppressed
|
||||||
by casting `person` to the `any` type.
|
by casting `person` to the `any` type.
|
||||||
|
|
||||||
```ts
|
```typescript
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-component',
|
selector: 'my-component',
|
||||||
template: '{{$any(person).addresss.street}}'
|
template: '{{$any(person).addresss.street}}'
|
||||||
|
@ -1289,4 +1290,3 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
|
||||||
* Macro-functions and macro-static methods.
|
* Macro-functions and macro-static methods.
|
||||||
* Compiler errors related to metadata.
|
* Compiler errors related to metadata.
|
||||||
* Validation of binding expressions
|
* Validation of binding expressions
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,13 @@ A basic understanding of the following:
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
An NgModule describes how the application parts fit together.
|
An NgModule describes how the application parts fit together.
|
||||||
Every application has at least one Angular module, the _root_ module
|
Every application has at least one Angular module, the _root_ module
|
||||||
that you bootstrap to launch the application.
|
that you bootstrap to launch the application.
|
||||||
By convention, it is usually called `AppModule`.
|
By convention, it is usually called `AppModule`.
|
||||||
|
|
||||||
If you use the CLI to generate an app, the default `AppModule` is as follows:
|
If you use the CLI to generate an app, the default `AppModule` is as follows:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
/* JavaScript imports */
|
/* JavaScript imports */
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
|
@ -49,10 +49,10 @@ The `@NgModule` decorator identifies `AppModule` as an `NgModule` class.
|
||||||
* **_declarations_**—this application's lone component.
|
* **_declarations_**—this application's lone component.
|
||||||
* **_imports_**—import `BrowserModule` to have browser specific services such as DOM rendering, sanitization, and location.
|
* **_imports_**—import `BrowserModule` to have browser specific services such as DOM rendering, sanitization, and location.
|
||||||
* **_providers_**—the service providers.
|
* **_providers_**—the service providers.
|
||||||
* **_bootstrap_**—the _root_ component that Angular creates and inserts
|
* **_bootstrap_**—the _root_ component that Angular creates and inserts
|
||||||
into the `index.html` host web page.
|
into the `index.html` host web page.
|
||||||
|
|
||||||
The default CLI application only has one component, `AppComponent`, so it
|
The default CLI application only has one component, `AppComponent`, so it
|
||||||
is in both the `declarations` and the `bootstrap` arrays.
|
is in both the `declarations` and the `bootstrap` arrays.
|
||||||
|
|
||||||
{@a declarations}
|
{@a declarations}
|
||||||
|
@ -62,23 +62,23 @@ is in both the `declarations` and the `bootstrap` arrays.
|
||||||
The module's `declarations` array tells Angular which components belong to that module.
|
The module's `declarations` array tells Angular which components belong to that module.
|
||||||
As you create more components, add them to `declarations`.
|
As you create more components, add them to `declarations`.
|
||||||
|
|
||||||
You must declare every component in exactly one `NgModule` class.
|
You must declare every component in exactly one `NgModule` class.
|
||||||
If you use a component without declaring it, Angular returns an
|
If you use a component without declaring it, Angular returns an
|
||||||
error message.
|
error message.
|
||||||
|
|
||||||
The `declarations` array only takes declarables. Declarables
|
The `declarations` array only takes declarables. Declarables
|
||||||
are components, [directives](guide/attribute-directives) and [pipes](guide/pipes).
|
are components, [directives](guide/attribute-directives) and [pipes](guide/pipes).
|
||||||
All of a module's declarables must be in the `declarations` array.
|
All of a module's declarables must be in the `declarations` array.
|
||||||
Declarables must belong to exactly one module. The compiler emits
|
Declarables must belong to exactly one module. The compiler emits
|
||||||
an error if you try to declare the same class in more than one module.
|
an error if you try to declare the same class in more than one module.
|
||||||
|
|
||||||
These declared classes are visible within the module but invisible
|
These declared classes are visible within the module but invisible
|
||||||
to components in a different module unless they are exported from
|
to components in a different module unless they are exported from
|
||||||
this module and the other module imports this one.
|
this module and the other module imports this one.
|
||||||
|
|
||||||
An example of what goes into a declarations array follows:
|
An example of what goes into a declarations array follows:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
declarations: [
|
declarations: [
|
||||||
YourComponent,
|
YourComponent,
|
||||||
YourPipe,
|
YourPipe,
|
||||||
|
@ -86,8 +86,8 @@ An example of what goes into a declarations array follows:
|
||||||
],
|
],
|
||||||
```
|
```
|
||||||
|
|
||||||
A declarable can only belong to one module, so only declare it in
|
A declarable can only belong to one module, so only declare it in
|
||||||
one `@NgModule`. When you need it elsewhere,
|
one `@NgModule`. When you need it elsewhere,
|
||||||
import the module that has the declarable you need in it.
|
import the module that has the declarable you need in it.
|
||||||
|
|
||||||
**Only `@NgModule` references** go in the `imports` array.
|
**Only `@NgModule` references** go in the `imports` array.
|
||||||
|
@ -103,13 +103,13 @@ To use a directive, component, or pipe in a module, you must do a few things:
|
||||||
3. Declare it in the `@NgModule` `declarations` array.
|
3. Declare it in the `@NgModule` `declarations` array.
|
||||||
|
|
||||||
|
|
||||||
Those three steps look like the following. In the file where you create your directive, export it.
|
Those three steps look like the following. In the file where you create your directive, export it.
|
||||||
The following example, named `ItemDirective` is the default directive structure that the CLI generates in its own file, `item.directive.ts`:
|
The following example, named `ItemDirective` is the default directive structure that the CLI generates in its own file, `item.directive.ts`:
|
||||||
|
|
||||||
<code-example path="bootstrapping/src/app/item.directive.ts" region="directive" title="src/app/item.directive.ts" linenums="false">
|
<code-example path="bootstrapping/src/app/item.directive.ts" region="directive" title="src/app/item.directive.ts" linenums="false">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
The key point here is that you have to export it so you can import it elsewhere. Next, import it
|
The key point here is that you have to export it so you can import it elsewhere. Next, import it
|
||||||
into the NgModule, in this example `app.module.ts`, with a JavaScript import statement:
|
into the NgModule, in this example `app.module.ts`, with a JavaScript import statement:
|
||||||
|
|
||||||
<code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" title="src/app/app.module.ts" linenums="false">
|
<code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" title="src/app/app.module.ts" linenums="false">
|
||||||
|
@ -136,11 +136,11 @@ The module's `imports` array appears exclusively in the `@NgModule` metadata obj
|
||||||
It tells Angular about other NgModules that this particular module needs to function properly.
|
It tells Angular about other NgModules that this particular module needs to function properly.
|
||||||
|
|
||||||
This list of modules are those that export components, directives, or pipes
|
This list of modules are those that export components, directives, or pipes
|
||||||
that the component templates in this module reference. In this case, the component is
|
that the component templates in this module reference. In this case, the component is
|
||||||
`AppComponent`, which references components, directives, or pipes in `BrowserModule`,
|
`AppComponent`, which references components, directives, or pipes in `BrowserModule`,
|
||||||
`FormsModule`, or `HttpModule`.
|
`FormsModule`, or `HttpModule`.
|
||||||
A component template can reference another component, directive,
|
A component template can reference another component, directive,
|
||||||
or pipe when the referenced class is declared in this module or
|
or pipe when the referenced class is declared in this module or
|
||||||
the class was imported from another module.
|
the class was imported from another module.
|
||||||
|
|
||||||
You don't have any services to provide yet.
|
You don't have any services to provide yet.
|
||||||
|
@ -150,32 +150,31 @@ But you will create some before long and you may chose to provide many of them h
|
||||||
|
|
||||||
## The `providers` array
|
## The `providers` array
|
||||||
|
|
||||||
The providers array is where you list the services the app needs. When
|
The providers array is where you list the services the app needs. When
|
||||||
you list services here, they are available app-wide. You can scope
|
you list services here, they are available app-wide. You can scope
|
||||||
them when using feature modules and lazy loading. For more information, see
|
them when using feature modules and lazy loading. For more information, see
|
||||||
[Providers](guide/providers).
|
[Providers](guide/providers).
|
||||||
|
|
||||||
## The `bootstrap` array
|
## The `bootstrap` array
|
||||||
|
|
||||||
The application launches by bootstrapping the root `AppModule`, which is
|
The application launches by bootstrapping the root `AppModule`, which is
|
||||||
also referred to as an `entryComponent`.
|
also referred to as an `entryComponent`.
|
||||||
Among other things, the bootstrapping process creates the component(s) listed in the `bootstrap` array
|
Among other things, the bootstrapping process creates the component(s) listed in the `bootstrap` array
|
||||||
and inserts each one into the browser DOM.
|
and inserts each one into the browser DOM.
|
||||||
|
|
||||||
Each bootstrapped component is the base of its own tree of components.
|
Each bootstrapped component is the base of its own tree of components.
|
||||||
Inserting a bootstrapped component usually triggers a cascade of
|
Inserting a bootstrapped component usually triggers a cascade of
|
||||||
component creations that fill out that tree.
|
component creations that fill out that tree.
|
||||||
|
|
||||||
While you can put more than one component tree on a host web page,
|
While you can put more than one component tree on a host web page,
|
||||||
most applications have only one component tree and bootstrap a single root component.
|
most applications have only one component tree and bootstrap a single root component.
|
||||||
|
|
||||||
This one root component is usually called `AppComponent` and is in the
|
This one root component is usually called `AppComponent` and is in the
|
||||||
root module's `bootstrap` array.
|
root module's `bootstrap` array.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## More about Angular Modules
|
## More about Angular Modules
|
||||||
|
|
||||||
For more on NgModules you're likely to see frequently in apps,
|
For more on NgModules you're likely to see frequently in apps,
|
||||||
see [Frequently Used Modules](#).
|
see [Frequently Used Modules](#).
|
||||||
|
|
||||||
|
|
|
@ -821,7 +821,7 @@ Here's an embedded live example for this guide. It has a custom image created fr
|
||||||
|
|
||||||
<live-example embedded img="guide/docs-style-guide/docs-style-guide-plunker.png"></live-example>
|
<live-example embedded img="guide/docs-style-guide/docs-style-guide-plunker.png"></live-example>
|
||||||
|
|
||||||
<a id="anchors"></a>
|
{@a anchors}
|
||||||
|
|
||||||
## Anchors
|
## Anchors
|
||||||
|
|
||||||
|
@ -861,12 +861,13 @@ Sometimes the section header text makes for an unattractive anchor. [This one](#
|
||||||
|
|
||||||
The greater danger is that **a future rewording of the header text would break** a link to this section.
|
The greater danger is that **a future rewording of the header text would break** a link to this section.
|
||||||
|
|
||||||
For these reasons, it is often wise to add a custom anchor explicitly, just above the heading or text to which it applies, using the special`{@ name}` syntax like this.
|
For these reasons, it is often wise to add a custom anchor explicitly, just above the heading or
|
||||||
|
text to which it applies, using the special `{@a name}` syntax like this.
|
||||||
|
|
||||||
<code-example language="html">
|
<code-example language="html">
|
||||||
{@a ugly-anchors}
|
{@a ugly-anchors}
|
||||||
|
|
||||||
#### Ugly, long section header anchors
|
#### Ugly, long section header anchors
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Now [link to that custom anchor name](#ugly-anchors) as you did before.
|
Now [link to that custom anchor name](#ugly-anchors) as you did before.
|
||||||
|
|
|
@ -9,7 +9,7 @@ Additional benefits of `HttpClient` include testability support, strong typing o
|
||||||
|
|
||||||
Before you can use the `HttpClient`, you need to install the `HttpClientModule` which provides it. This can be done in your application module, and is only necessary once.
|
Before you can use the `HttpClient`, you need to install the `HttpClientModule` which provides it. This can be done in your application module, and is only necessary once.
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
// app.module.ts:
|
// app.module.ts:
|
||||||
|
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
|
@ -48,7 +48,7 @@ The most common type of request applications make to a backend is to request JSO
|
||||||
The `get()` method on `HttpClient` makes accessing this data straightforward.
|
The `get()` method on `HttpClient` makes accessing this data straightforward.
|
||||||
|
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
@Component(...)
|
@Component(...)
|
||||||
export class MyComponent implements OnInit {
|
export class MyComponent implements OnInit {
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ In the above example, the `data['results']` field access stands out because you
|
||||||
You can, however, tell `HttpClient` what type the response will be, which is recommended.
|
You can, however, tell `HttpClient` what type the response will be, which is recommended.
|
||||||
To do so, first you define an interface with the correct shape:
|
To do so, first you define an interface with the correct shape:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
interface ItemsResponse {
|
interface ItemsResponse {
|
||||||
results: string[];
|
results: string[];
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ interface ItemsResponse {
|
||||||
|
|
||||||
Then, when you make the `HttpClient.get` call, pass a type parameter:
|
Then, when you make the `HttpClient.get` call, pass a type parameter:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
http.get<ItemsResponse>('/api/items').subscribe(data => {
|
http.get<ItemsResponse>('/api/items').subscribe(data => {
|
||||||
// data is now an instance of type ItemsResponse, so you can do this:
|
// data is now an instance of type ItemsResponse, so you can do this:
|
||||||
this.results = data.results;
|
this.results = data.results;
|
||||||
|
@ -94,7 +94,7 @@ http.get<ItemsResponse>('/api/items').subscribe(data => {
|
||||||
|
|
||||||
The response body doesn't return all the data you may need. Sometimes servers return special headers or status codes to indicate certain conditions, and inspecting those can be necessary. To do this, you can tell `HttpClient` you want the full response instead of just the body with the `observe` option:
|
The response body doesn't return all the data you may need. Sometimes servers return special headers or status codes to indicate certain conditions, and inspecting those can be necessary. To do this, you can tell `HttpClient` you want the full response instead of just the body with the `observe` option:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
http
|
http
|
||||||
.get<MyJsonData>('/data.json', {observe: 'response'})
|
.get<MyJsonData>('/data.json', {observe: 'response'})
|
||||||
.subscribe(resp => {
|
.subscribe(resp => {
|
||||||
|
@ -116,7 +116,7 @@ What happens if the request fails on the server, or if a poor network connection
|
||||||
|
|
||||||
To handle it, add an error handler to your `.subscribe()` call:
|
To handle it, add an error handler to your `.subscribe()` call:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
http
|
http
|
||||||
.get<ItemsResponse>('/api/items')
|
.get<ItemsResponse>('/api/items')
|
||||||
.subscribe(
|
.subscribe(
|
||||||
|
@ -137,7 +137,7 @@ There are two types of errors that can occur. If the backend returns an unsucces
|
||||||
|
|
||||||
In both cases, you can look at the `HttpErrorResponse` to figure out what happened.
|
In both cases, you can look at the `HttpErrorResponse` to figure out what happened.
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
http
|
http
|
||||||
.get<ItemsResponse>('/api/items')
|
.get<ItemsResponse>('/api/items')
|
||||||
.subscribe(
|
.subscribe(
|
||||||
|
@ -169,7 +169,7 @@ import 'rxjs/add/operator/retry';
|
||||||
|
|
||||||
Then, you can use it with HTTP Observables like this:
|
Then, you can use it with HTTP Observables like this:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
http
|
http
|
||||||
.get<ItemsResponse>('/api/items')
|
.get<ItemsResponse>('/api/items')
|
||||||
// Retry this request up to 3 times.
|
// Retry this request up to 3 times.
|
||||||
|
@ -182,7 +182,7 @@ http
|
||||||
|
|
||||||
Not all APIs return JSON data. Suppose you want to read a text file on the server. You have to tell `HttpClient` that you expect a textual response:
|
Not all APIs return JSON data. Suppose you want to read a text file on the server. You have to tell `HttpClient` that you expect a textual response:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
http
|
http
|
||||||
.get('/textfile.txt', {responseType: 'text'})
|
.get('/textfile.txt', {responseType: 'text'})
|
||||||
// The Observable returned by get() is of type Observable<string>
|
// The Observable returned by get() is of type Observable<string>
|
||||||
|
@ -200,7 +200,7 @@ In addition to fetching data from the server, `HttpClient` supports mutating req
|
||||||
One common operation is to POST data to a server; for example when submitting a form. The code for
|
One common operation is to POST data to a server; for example when submitting a form. The code for
|
||||||
sending a POST request is very similar to the code for GET:
|
sending a POST request is very similar to the code for GET:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
const body = {name: 'Brad'};
|
const body = {name: 'Brad'};
|
||||||
|
|
||||||
http
|
http
|
||||||
|
@ -212,7 +212,7 @@ http
|
||||||
|
|
||||||
*Note the `subscribe()` method.* All Observables returned from `HttpClient` are _cold_, which is to say that they are _blueprints_ for making requests. Nothing will happen until you call `subscribe()`, and every such call will make a separate request. For example, this code sends a POST request with the same data twice:
|
*Note the `subscribe()` method.* All Observables returned from `HttpClient` are _cold_, which is to say that they are _blueprints_ for making requests. Nothing will happen until you call `subscribe()`, and every such call will make a separate request. For example, this code sends a POST request with the same data twice:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
const req = http.post('/api/items/add', body);
|
const req = http.post('/api/items/add', body);
|
||||||
// 0 requests made - .subscribe() not called.
|
// 0 requests made - .subscribe() not called.
|
||||||
req.subscribe();
|
req.subscribe();
|
||||||
|
@ -230,7 +230,7 @@ Besides the URL and a possible request body, there are other aspects of an outgo
|
||||||
|
|
||||||
One common task is adding an `Authorization` header to outgoing requests. Here's how you do that:
|
One common task is adding an `Authorization` header to outgoing requests. Here's how you do that:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
http
|
http
|
||||||
.post('/api/items/add', body, {
|
.post('/api/items/add', body, {
|
||||||
headers: new HttpHeaders().set('Authorization', 'my-auth-token'),
|
headers: new HttpHeaders().set('Authorization', 'my-auth-token'),
|
||||||
|
@ -244,7 +244,7 @@ The `HttpHeaders` class is immutable, so every `set()` returns a new instance an
|
||||||
|
|
||||||
Adding URL parameters works in the same way. To send a request with the `id` parameter set to `3`, you would do:
|
Adding URL parameters works in the same way. To send a request with the `id` parameter set to `3`, you would do:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
http
|
http
|
||||||
.post('/api/items/add', body, {
|
.post('/api/items/add', body, {
|
||||||
params: new HttpParams().set('id', '3'),
|
params: new HttpParams().set('id', '3'),
|
||||||
|
@ -269,7 +269,7 @@ before sending it to the server, and the interceptors can transform the response
|
||||||
To implement an interceptor, you declare a class that implements `HttpInterceptor`, which
|
To implement an interceptor, you declare a class that implements `HttpInterceptor`, which
|
||||||
has a single `intercept()` method. Here is a simple interceptor which does nothing but forward the request through without altering it:
|
has a single `intercept()` method. Here is a simple interceptor which does nothing but forward the request through without altering it:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
|
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
|
||||||
|
|
||||||
|
@ -295,7 +295,7 @@ This pattern is similar to those in middleware frameworks such as Express.js.
|
||||||
|
|
||||||
Simply declaring the `NoopInterceptor` above doesn't cause your app to use it. You need to wire it up in your app module by providing it as an interceptor, as follows:
|
Simply declaring the `NoopInterceptor` above doesn't cause your app to use it. You need to wire it up in your app module by providing it as an interceptor, as follows:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {HTTP_INTERCEPTORS} from '@angular/common/http';
|
import {HTTP_INTERCEPTORS} from '@angular/common/http';
|
||||||
|
|
||||||
|
@ -338,7 +338,7 @@ If you have a need to mutate the request body, you need to copy the request body
|
||||||
|
|
||||||
Since requests are immutable, they cannot be modified directly. To mutate them, use `clone()`:
|
Since requests are immutable, they cannot be modified directly. To mutate them, use `clone()`:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
// This is a duplicate. It is exactly the same as the original.
|
// This is a duplicate. It is exactly the same as the original.
|
||||||
const dupReq = req.clone();
|
const dupReq = req.clone();
|
||||||
|
@ -354,7 +354,7 @@ As you can see, the hash accepted by `clone()` allows you to mutate specific pro
|
||||||
|
|
||||||
A common use of interceptors is to set default headers on outgoing responses. For example, assuming you have an injectable `AuthService` which can provide an authentication token, here is how you would write an interceptor which adds it to all outgoing requests:
|
A common use of interceptors is to set default headers on outgoing responses. For example, assuming you have an injectable `AuthService` which can provide an authentication token, here is how you would write an interceptor which adds it to all outgoing requests:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
|
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
|
||||||
|
|
||||||
|
@ -375,7 +375,7 @@ export class AuthInterceptor implements HttpInterceptor {
|
||||||
|
|
||||||
The practice of cloning a request to set new headers is so common that there's actually a shortcut for it:
|
The practice of cloning a request to set new headers is so common that there's actually a shortcut for it:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
const authReq = req.clone({setHeaders: {Authorization: authHeader}});
|
const authReq = req.clone({setHeaders: {Authorization: authHeader}});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -389,7 +389,7 @@ An interceptor that alters headers can be used for a number of different operati
|
||||||
|
|
||||||
Because interceptors can process the request and response _together_, they can do things like log or time requests. Consider this interceptor which uses `console.log` to show how long each request takes:
|
Because interceptors can process the request and response _together_, they can do things like log or time requests. Consider this interceptor which uses `console.log` to show how long each request takes:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
import 'rxjs/add/operator/do';
|
import 'rxjs/add/operator/do';
|
||||||
|
|
||||||
export class TimingInterceptor implements HttpInterceptor {
|
export class TimingInterceptor implements HttpInterceptor {
|
||||||
|
@ -414,7 +414,7 @@ Notice the RxJS `do()` operator—it adds a side effect to an Observable wit
|
||||||
|
|
||||||
You can also use interceptors to implement caching. For this example, assume that you've written an HTTP cache with a simple interface:
|
You can also use interceptors to implement caching. For this example, assume that you've written an HTTP cache with a simple interface:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
abstract class HttpCache {
|
abstract class HttpCache {
|
||||||
/**
|
/**
|
||||||
* Returns a cached response, if any, or null if not present.
|
* Returns a cached response, if any, or null if not present.
|
||||||
|
@ -430,7 +430,7 @@ abstract class HttpCache {
|
||||||
|
|
||||||
An interceptor can apply this cache to outgoing requests.
|
An interceptor can apply this cache to outgoing requests.
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CachingInterceptor implements HttpInterceptor {
|
export class CachingInterceptor implements HttpInterceptor {
|
||||||
constructor(private cache: HttpCache) {}
|
constructor(private cache: HttpCache) {}
|
||||||
|
@ -467,7 +467,7 @@ Obviously this example glosses over request matching, cache invalidation, etc.,
|
||||||
|
|
||||||
To really demonstrate their flexibility, you can change the above example to return _two_ response events if the request exists in cache—the cached response first, and an updated network response later.
|
To really demonstrate their flexibility, you can change the above example to return _two_ response events if the request exists in cache—the cached response first, and an updated network response later.
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
// Still skip non-GET requests.
|
// Still skip non-GET requests.
|
||||||
if (req.method !== 'GET') {
|
if (req.method !== 'GET') {
|
||||||
|
@ -507,7 +507,7 @@ Sometimes applications need to transfer large amounts of data, and those transfe
|
||||||
|
|
||||||
To make a request with progress events enabled, first create an instance of `HttpRequest` with the special `reportProgress` option set:
|
To make a request with progress events enabled, first create an instance of `HttpRequest` with the special `reportProgress` option set:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
const req = new HttpRequest('POST', '/upload/file', file, {
|
const req = new HttpRequest('POST', '/upload/file', file, {
|
||||||
reportProgress: true,
|
reportProgress: true,
|
||||||
});
|
});
|
||||||
|
@ -518,7 +518,7 @@ change detection, so only turn them on if you intend to actually update the UI o
|
||||||
|
|
||||||
Next, make the request through the `request()` method of `HttpClient`. The result will be an Observable of events, just like with interceptors:
|
Next, make the request through the `request()` method of `HttpClient`. The result will be an Observable of events, just like with interceptors:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
http.request(req).subscribe(event => {
|
http.request(req).subscribe(event => {
|
||||||
// Via this API, you get access to the raw event stream.
|
// Via this API, you get access to the raw event stream.
|
||||||
// Look for upload progress events.
|
// Look for upload progress events.
|
||||||
|
@ -553,7 +553,7 @@ In order to prevent collisions in environments where multiple Angular apps share
|
||||||
|
|
||||||
If your backend service uses different names for the XSRF token cookie or header, use `HttpClientXsrfModule.withOptions()` to override the defaults.
|
If your backend service uses different names for the XSRF token cookie or header, use `HttpClientXsrfModule.withOptions()` to override the defaults.
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
imports: [
|
imports: [
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
HttpClientXsrfModule.withOptions({
|
HttpClientXsrfModule.withOptions({
|
||||||
|
@ -575,7 +575,7 @@ Angular's HTTP testing library is designed for a pattern of testing where the ap
|
||||||
|
|
||||||
To begin testing requests made through `HttpClient`, import `HttpClientTestingModule` and add it to your `TestBed` setup, like so:
|
To begin testing requests made through `HttpClient`, import `HttpClientTestingModule` and add it to your `TestBed` setup, like so:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
|
|
||||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||||
|
|
||||||
|
@ -595,7 +595,7 @@ That's it. Now requests made in the course of your tests will hit the testing ba
|
||||||
|
|
||||||
With the mock installed via the module, you can write a test that expects a GET Request to occur and provides a mock response. The following example does this by injecting both the `HttpClient` into the test and a class called `HttpTestingController`
|
With the mock installed via the module, you can write a test that expects a GET Request to occur and provides a mock response. The following example does this by injecting both the `HttpClient` into the test and a class called `HttpTestingController`
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
it('expects a GET request', inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
|
it('expects a GET request', inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
|
||||||
// Make an HTTP GET request, and expect that it return an object
|
// Make an HTTP GET request, and expect that it return an object
|
||||||
// of the form {name: 'Test Data'}.
|
// of the form {name: 'Test Data'}.
|
||||||
|
@ -624,7 +624,7 @@ it('expects a GET request', inject([HttpClient, HttpTestingController], (http: H
|
||||||
|
|
||||||
The last step, verifying that no requests remain outstanding, is common enough for you to move it into an `afterEach()` step:
|
The last step, verifying that no requests remain outstanding, is common enough for you to move it into an `afterEach()` step:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
|
afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
|
||||||
httpMock.verify();
|
httpMock.verify();
|
||||||
}));
|
}));
|
||||||
|
@ -634,7 +634,7 @@ afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
|
||||||
|
|
||||||
If matching by URL isn't sufficient, it's possible to implement your own matching function. For example, you could look for an outgoing request that has an Authorization header:
|
If matching by URL isn't sufficient, it's possible to implement your own matching function. For example, you could look for an outgoing request that has an Authorization header:
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
const req = httpMock.expectOne((req) => req.headers.has('Authorization'));
|
const req = httpMock.expectOne((req) => req.headers.has('Authorization'));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -644,7 +644,7 @@ Just as with the `expectOne()` by URL in the test above, if 0 or 2+ requests mat
|
||||||
|
|
||||||
If you need to respond to duplicate requests in your test, use the `match()` API instead of `expectOne()`, which takes the same arguments but returns an array of matching requests. Once returned, these requests are removed from future matching and are your responsibility to verify and flush.
|
If you need to respond to duplicate requests in your test, use the `match()` API instead of `expectOne()`, which takes the same arguments but returns an array of matching requests. Once returned, these requests are removed from future matching and are your responsibility to verify and flush.
|
||||||
|
|
||||||
```javascript
|
```typescript
|
||||||
// Expect that 5 pings have been made and flush them.
|
// Expect that 5 pings have been made and flush them.
|
||||||
const reqs = httpMock.match('/ping');
|
const reqs = httpMock.match('/ping');
|
||||||
expect(reqs.length).toBe(5);
|
expect(reqs.length).toBe(5);
|
||||||
|
|
Loading…
Reference in New Issue