mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
108 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b31f5dd2f0 | |||
| 2548712aba | |||
| f4fa4afd04 | |||
| 439d77e852 | |||
| 036f740f77 | |||
| e10aa8858f | |||
| 38d23af419 | |||
| 923a7446a2 | |||
| 874d78b502 | |||
| 8d18969714 | |||
| 2106b74853 | |||
| 5ff715c549 | |||
| 30c9e80a30 | |||
| 0392feb135 | |||
| 6d215d3124 | |||
| e46972ac4b | |||
| 2e42bb9c62 | |||
| d14235cfb1 | |||
| befd650a78 | |||
| fd2abebf91 | |||
| 387f4a79f8 | |||
| 8f32c09872 | |||
| 04b3497db1 | |||
| d0e3ad5300 | |||
| c7fed38cf0 | |||
| 1d39ab6e6b | |||
| fce4ea1d8d | |||
| 2a833e6eac | |||
| d0f4f1d601 | |||
| 3ee883e417 | |||
| b868f1c94e | |||
| efb8e3e431 | |||
| 8085fe34f1 | |||
| 9edfe4ac97 | |||
| 79825d3f10 | |||
| 4e9492cf6d | |||
| 3f162f5e3f | |||
| b6445c4cd6 | |||
| d05d05e48e | |||
| 7a7452dc28 | |||
| 05f3f7445a | |||
| 6307f3586e | |||
| ce6ad5a66a | |||
| cbfd91b0f2 | |||
| 8cd95d4901 | |||
| ec00075a2f | |||
| a0a635322c | |||
| 8dcd3cd263 | |||
| 677fe6a1cc | |||
| 5d8394cc8c | |||
| acdb28dc1d | |||
| c5a5165294 | |||
| 71831c63ba | |||
| 3511373e22 | |||
| ff7c71653a | |||
| 6b779b11d1 | |||
| 1eb77a2f4f | |||
| 929d69e62f | |||
| f5d764d75c | |||
| 55f485b3bb | |||
| 3606917732 | |||
| 0cbbd6aeec | |||
| a8e9247e6a | |||
| 793326deef | |||
| 10d46b4247 | |||
| b744bf6a08 | |||
| 2e5bd88ebf | |||
| 9b8ea9b5ca | |||
| eb91035102 | |||
| 17e2a2a9d1 | |||
| b431b5c6d6 | |||
| bc371dac44 | |||
| 36361b0506 | |||
| 38f53a55c3 | |||
| 8de3d099d2 | |||
| 945a3ad359 | |||
| 88003e27db | |||
| a4cba79440 | |||
| 6ca7a79bfd | |||
| e95ee96562 | |||
| 536ded2280 | |||
| 6b8e60c06a | |||
| 5004b6ebf1 | |||
| 6c08635662 | |||
| f0add81caf | |||
| 21e7584c8c | |||
| 92c9661165 | |||
| a462f91d3e | |||
| aa8d3ed69b | |||
| 2ca404dbfd | |||
| f9edb776ca | |||
| c195c3f73c | |||
| 114011d2a0 | |||
| b5153814af | |||
| e8e8e5f171 | |||
| 08fb7bc4ca | |||
| 6d709273eb | |||
| 571d7debb5 | |||
| b1ba6429d4 | |||
| 6c104a28e0 | |||
| 5e09cd1f67 | |||
| 6a7b818d94 | |||
| 9ecaa05c7d | |||
| d36a9e6bf3 | |||
| 4b452ffd3d | |||
| 3f2d16c823 | |||
| 4dca1842b3 | |||
| 442b16c551 |
@@ -96,11 +96,11 @@ build:remote --cpu=k8
|
||||
build:remote --host_cpu=k8
|
||||
|
||||
# Toolchain and platform related flags
|
||||
build:remote --crosstool_top=@npm//@angular/dev-infra-private/bazel/remote-execution/cpp:cc_toolchain_suite
|
||||
build:remote --extra_toolchains=@npm//@angular/dev-infra-private/bazel/remote-execution/cpp:cc_toolchain
|
||||
build:remote --extra_execution_platforms=@npm//@angular/dev-infra-private/bazel/remote-execution:platform
|
||||
build:remote --host_platform=@npm//@angular/dev-infra-private/bazel/remote-execution:platform
|
||||
build:remote --platforms=@npm//@angular/dev-infra-private/bazel/remote-execution:platform
|
||||
build:remote --crosstool_top=@npm//@angular/build-tooling/bazel/remote-execution/cpp:cc_toolchain_suite
|
||||
build:remote --extra_toolchains=@npm//@angular/build-tooling/bazel/remote-execution/cpp:cc_toolchain
|
||||
build:remote --extra_execution_platforms=@npm//@angular/build-tooling/bazel/remote-execution:platform
|
||||
build:remote --host_platform=@npm//@angular/build-tooling/bazel/remote-execution:platform
|
||||
build:remote --platforms=@npm//@angular/build-tooling/bazel/remote-execution:platform
|
||||
|
||||
# Remote instance and caching
|
||||
build:remote --remote_instance_name=projects/internal-200822/instances/primary_instance
|
||||
|
||||
@@ -24,15 +24,15 @@ version: 2.1
|
||||
# **NOTE 2 **: If you change the cache key prefix, also sync the cache_key_fallback to match.
|
||||
# **NOTE 3 **: Keep the static part of the cache key as prefix to enable correct fallbacks.
|
||||
# See https://circleci.com/docs/2.0/caching/#restoring-cache for how prefixes work in CircleCI.
|
||||
var_3: &cache_key v6-angular-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "aio/yarn.lock" }}
|
||||
var_3: &cache_key v7-angular-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "aio/yarn.lock" }}
|
||||
# We invalidate the cache if the Bazel version changes because otherwise the `bazelisk` cache
|
||||
# folder will contain all previously used versions and ultimately cause the cache restoring to
|
||||
# be slower due to its growing size.
|
||||
var_4: &cache_key_fallback v6-angular-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}
|
||||
var_4: &cache_key_fallback v7-angular-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}
|
||||
|
||||
# Windows needs its own cache key because binaries in node_modules are different.
|
||||
var_3_win: &cache_key_win v8-angular-win-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}
|
||||
var_4_win: &cache_key_win_fallback v8-angular-win-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}
|
||||
var_3_win: &cache_key_win v9-angular-win-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}
|
||||
var_4_win: &cache_key_win_fallback v9-angular-win-node-14-{{ checksum "month.txt" }}-{{ checksum ".bazelversion" }}
|
||||
|
||||
# Cache key for the `components-repo-unit-tests` job. **Note** when updating the SHA in the
|
||||
# cache keys also update the SHA for the "COMPONENTS_REPO_COMMIT" environment variable.
|
||||
|
||||
@@ -12,7 +12,7 @@ Info on remote development and developing inside a container with VSCode:
|
||||
|
||||
_Prerequisite: [Install Docker](https://docs.docker.com/install) on your local environment._
|
||||
|
||||
To get started, read and follow the instuctions in [Developing inside a Container](https://code.visualstudio.com/docs/remote/containers). The [.devcontainer/](.) directory contains pre-configured `devcontainer.json` and `Dockerfile` files, which you can use to set up remote development with a docker container.
|
||||
To get started, read and follow the instructions in [Developing inside a Container](https://code.visualstudio.com/docs/remote/containers). The [.devcontainer/](.) directory contains pre-configured `devcontainer.json` and `Dockerfile` files, which you can use to set up remote development with a docker container.
|
||||
|
||||
In a nutshell, you need to:
|
||||
- Install the [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension.
|
||||
|
||||
@@ -13,13 +13,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3.0.2
|
||||
- uses: angular/dev-infra/github-actions/commit-message-based-labels@8420d8593135df75b283e90beba0aa9b5b9838ce
|
||||
- uses: angular/dev-infra/github-actions/commit-message-based-labels@22d3067021130271afcfd02d063828c5bdd9c2d7
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
post_approval_changes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3.0.2
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@8420d8593135df75b283e90beba0aa9b5b9838ce
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@22d3067021130271afcfd02d063828c5bdd9c2d7
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -14,6 +14,6 @@ jobs:
|
||||
if: github.repository == 'angular/angular'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: angular/dev-infra/github-actions/feature-request@8420d8593135df75b283e90beba0aa9b5b9838ce
|
||||
- uses: angular/dev-infra/github-actions/feature-request@22d3067021130271afcfd02d063828c5bdd9c2d7
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -14,6 +14,6 @@ jobs:
|
||||
if: github.repository == 'angular/angular'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: angular/dev-infra/github-actions/lock-closed@8420d8593135df75b283e90beba0aa9b5b9838ce
|
||||
- uses: angular/dev-infra/github-actions/lock-closed@22d3067021130271afcfd02d063828c5bdd9c2d7
|
||||
with:
|
||||
lock-bot-key: ${{ secrets.LOCK_BOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -45,6 +45,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: 'Upload to code-scanning'
|
||||
uses: github/codeql-action/upload-sarif@3f62b754e23e0dd60f91b744033e1dc1654c0ec6 # tag=v2.1.15
|
||||
uses: github/codeql-action/upload-sarif@2ca79b6fa8d3ec278944088b4aa5f46912db5d63 # tag=v2.1.18
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {CaretakerConfig} from '@angular/dev-infra-private/ng-dev';
|
||||
import {CaretakerConfig} from '@angular/ng-dev';
|
||||
|
||||
/** The configuration for `ng-dev caretaker` commands. */
|
||||
export const caretaker: CaretakerConfig = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {CommitMessageConfig} from '@angular/dev-infra-private/ng-dev';
|
||||
import {CommitMessageConfig} from '@angular/ng-dev';
|
||||
|
||||
/**
|
||||
* The configuration for `ng-dev commit-message` commands.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import {FormatConfig} from '@angular/dev-infra-private/ng-dev';
|
||||
import {FormatConfig} from '@angular/ng-dev';
|
||||
|
||||
/**
|
||||
* Configuration for the `ng-dev format` command.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import {GithubConfig} from '@angular/dev-infra-private/ng-dev';
|
||||
import {GithubConfig} from '@angular/ng-dev';
|
||||
|
||||
/**
|
||||
* Github configuration for the `ng-dev` command. This repository is used as
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {PullRequestConfig} from '@angular/dev-infra-private/ng-dev';
|
||||
import {PullRequestConfig} from '@angular/ng-dev';
|
||||
|
||||
/**
|
||||
* Configuration for the merge tool in `ng-dev`. This sets up the labels which
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import {ReleaseConfig} from '@angular/dev-infra-private/ng-dev';
|
||||
import {ReleaseConfig} from '@angular/ng-dev';
|
||||
|
||||
/** Configuration for the `ng-dev release` command. */
|
||||
export const release: ReleaseConfig = {
|
||||
|
||||
+10
-5
@@ -58,13 +58,13 @@
|
||||
# josmar-crwdstffng
|
||||
# ileil
|
||||
# TeriGlover
|
||||
# TMDavisGoogle
|
||||
# bob-watson
|
||||
|
||||
version: 3
|
||||
|
||||
#availability:
|
||||
# users_unavailable:
|
||||
# - username
|
||||
availability:
|
||||
users_unavailable:
|
||||
- atscott # August 15 - September 20 (at least)
|
||||
|
||||
# Meta field that goes unused by PullApprove to allow for defining aliases to be
|
||||
# used throughout the config.
|
||||
@@ -240,6 +240,8 @@ groups:
|
||||
'aio/content/examples/component-styles/**/{*,.*}',
|
||||
'aio/content/examples/content-projection/**/{*,.*}',
|
||||
'aio/content/guide/content-projection.md',
|
||||
'aio/content/guide/creating-injectable-service.md',
|
||||
'aio/content/guide/dependency-injection-overview.md',
|
||||
'aio/content/guide/dependency-injection.md',
|
||||
'aio/content/examples/dependency-injection/**/{*,.*}',
|
||||
'aio/content/images/guide/dependency-injection/**/{*,.*}',
|
||||
@@ -1054,6 +1056,8 @@ groups:
|
||||
'aio/content/guide/docs-style-guide.md',
|
||||
'aio/content/examples/docs-style-guide/**/{*,.*}',
|
||||
'aio/content/images/guide/docs-style-guide/**/{*,.*}',
|
||||
'aio/content/guide/docs-lint-errors.md',
|
||||
'aio/content/images/guide/docs-lint-errors/**/{*,.*}',
|
||||
'aio/content/guide/localized-documentation.md',
|
||||
'aio/content/guide/localizing-angular.md',
|
||||
'aio/content/guide/reviewing-content.md',
|
||||
@@ -1062,8 +1066,9 @@ groups:
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- alxhub
|
||||
- AndrewKushnir
|
||||
- gkalpak
|
||||
- jessicajaniuk
|
||||
- josephperrott
|
||||
|
||||
# =========================================================
|
||||
|
||||
Vendored
+1
@@ -11,5 +11,6 @@
|
||||
// The following extensions are useful when working on angular.io (i.e. inside the `aio/` directory).
|
||||
//"angular.ng-template",
|
||||
//"dbaeumer.vscode-eslint",
|
||||
//"errata-ai.vale-server",
|
||||
],
|
||||
}
|
||||
|
||||
+99
-131
@@ -1,3 +1,102 @@
|
||||
<a name="14.1.2"></a>
|
||||
# 14.1.2 (2022-08-10)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [5ff715c549](https://github.com/angular/angular/commit/5ff715c5497fcbcbb33eb93770470fff5a816cd5) | fix | check if transplanted views are attached to change detector ([#46974](https://github.com/angular/angular/pull/46974)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [439d77e852](https://github.com/angular/angular/commit/439d77e852c2e08d384c420a2c3a962a804c60f1) | fix | Fix route recognition behavior with some versions of rxjs ([#47098](https://github.com/angular/angular/pull/47098)) ([#47112](https://github.com/angular/angular/pull/47112)) |
|
||||
## Special Thanks
|
||||
4javier, Andrew Kushnir, Andrew Scott, AntonioCardenas, Bob Watson, Bruno Barbosa, Eduardo Speroni, Edward, George Kalpakas, Jan Melcher, Kristiyan Kostadinov, Mladen Jakovljević, Paul Gschwendtner, Pawel Kozlowski, Roman Matusevich, Vovch, ashide2729, ileil and onrails
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.1.1"></a>
|
||||
# 14.1.1 (2022-08-03)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [3606917732](https://github.com/angular/angular/commit/3606917732e5ad887426c1cbccf6e375eff905d6) | fix | improve the missing control flow directive message ([#46903](https://github.com/angular/angular/pull/46903)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [79825d3f10](https://github.com/angular/angular/commit/79825d3f1078c9b91eeb5e4699718ccde6c458b5) | fix | Do not call preload method when not necessary ([#47007](https://github.com/angular/angular/pull/47007)) |
|
||||
| [05f3f7445a](https://github.com/angular/angular/commit/05f3f7445a0bbe3c7ffed3aec308ca8888e77d99) | fix | Use correct return type for provideRoutes function ([#46941](https://github.com/angular/angular/pull/46941)) |
|
||||
## Special Thanks
|
||||
Alan Agius, Andrew Kushnir, Andrew Quinn, Andrew Scott, Aristeidis Bampakos, Asaf M, Bob Watson, Cédric Exbrayat, Durairaj Subramaniam, George Kalpakas, Ivaylo Kirov, J Rob Gant, Kristiyan Kostadinov, Marek Hám, Paul Gschwendtner, Roman Matusevich and Simona Cotin
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.1.0"></a>
|
||||
# 14.1.0 (2022-07-20)
|
||||
## Deprecations
|
||||
### core
|
||||
- The `createNgModuleRef` is deprecated in favor of newly added `createNgModule` one.
|
||||
- The bit field signature of `inject()` has been deprecated, in favor of the
|
||||
new options object. Correspondingly, `InjectFlags` is deprecated as well.
|
||||
### animations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [55308f2df5](https://github.com/angular/angular/commit/55308f2df5b0f6e8e40e3c4085c463a5b83c5ed1) | feat | add `provideAnimations()` and `provideNoopAnimations()` functions ([#46793](https://github.com/angular/angular/pull/46793)) |
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [4a2e7335b1](https://github.com/angular/angular/commit/4a2e7335b180190800cf2c5db8ed1c8841dbf473) | feat | make the `CommonModule` pipes standalone ([#46401](https://github.com/angular/angular/pull/46401)) |
|
||||
| [a7597dd080](https://github.com/angular/angular/commit/a7597dd08026a4071758323d54ccbfb382e0c780) | feat | make the CommonModule directives standalone ([#46469](https://github.com/angular/angular/pull/46469)) |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [33ce3883a5](https://github.com/angular/angular/commit/33ce3883a5d962adf5ee7feffd3426feefe0c0b5) | feat | Add extended diagnostic to warn when missing let on ngForOf ([#46683](https://github.com/angular/angular/pull/46683)) |
|
||||
| [6f11a58040](https://github.com/angular/angular/commit/6f11a580406877e440c43df31fae3d5f120cafed) | feat | Add extended diagnostic to warn when text attributes are intended to be bindings ([#46161](https://github.com/angular/angular/pull/46161)) |
|
||||
| [9e836c232f](https://github.com/angular/angular/commit/9e836c232ff66043bc101b905dae4c8bde18bc58) | feat | warn when style suffixes are used with attribute bindings ([#46651](https://github.com/angular/angular/pull/46651)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [93c65e7b14](https://github.com/angular/angular/commit/93c65e7b1468bb0c696dec1bc3362422a2ca5170) | feat | add extended diagnostic for non-nullable optional chains ([#46686](https://github.com/angular/angular/pull/46686)) |
|
||||
| [131d029da1](https://github.com/angular/angular/commit/131d029da16b7d486cdc200f00160b9a11871fb2) | feat | detect missing control flow directive imports in standalone components ([#46146](https://github.com/angular/angular/pull/46146)) |
|
||||
| [6b8e60c06a](https://github.com/angular/angular/commit/6b8e60c06a4f9a5fdbce9e7971d403ccb2bc6e8e) | fix | improve the missingControlFlowDirective message ([#46846](https://github.com/angular/angular/pull/46846)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [e8e8e5f171](https://github.com/angular/angular/commit/e8e8e5f1718f605c62a671b0ff15fa4dff7d8229) | feat | add `createComponent` function |
|
||||
| [b5153814af](https://github.com/angular/angular/commit/b5153814af3e6b1ec8550ddf39584efd7cca36be) | feat | add `reflectComponentType` function |
|
||||
| [96c6139c9a](https://github.com/angular/angular/commit/96c6139c9ab35aa6ab2330a5a79a5906d5c2e8be) | feat | add ability to set inputs on ComponentRef ([#46641](https://github.com/angular/angular/pull/46641)) |
|
||||
| [a6d5fe202c](https://github.com/angular/angular/commit/a6d5fe202cafb419f3beb8d09711132124b6aa9a) | feat | alias `createNgModuleRef` as `createNgModule` ([#46789](https://github.com/angular/angular/pull/46789)) |
|
||||
| [71e606d3c3](https://github.com/angular/angular/commit/71e606d3c3cfdcf93a6e40f84fd69aa75c5cca42) | feat | expose EnvironmentInjector on ApplicationRef ([#46665](https://github.com/angular/angular/pull/46665)) |
|
||||
| [19e6d9ccd3](https://github.com/angular/angular/commit/19e6d9ccd36c7776fcee7de541bba413fd6dcabf) | feat | import AsyncStackTaggingZone if available ([#46693](https://github.com/angular/angular/pull/46693)) |
|
||||
| [a7a14df5f8](https://github.com/angular/angular/commit/a7a14df5f8ff2d1e6a4dba3ac53f4479a6646810) | feat | introduce `EnvironmentInjector.runInContext` API ([#46653](https://github.com/angular/angular/pull/46653)) |
|
||||
| [fa52b6e906](https://github.com/angular/angular/commit/fa52b6e906e549e1c6b4a4f4428596d093fb0549) | feat | options object to supersede bit flags for `inject()` ([#46649](https://github.com/angular/angular/pull/46649)) |
|
||||
| [af20112222](https://github.com/angular/angular/commit/af20112222fcfa961ff9a2dee4050dd59aa4156e) | feat | support the descendants option for ContentChild queries ([#46638](https://github.com/angular/angular/pull/46638)) |
|
||||
| [945a3ad359](https://github.com/angular/angular/commit/945a3ad359cd2fe3456f635b0fe36effbfe8d5c2) | fix | Fix `runInContext` for `NgModuleRef` injector ([#46877](https://github.com/angular/angular/pull/46877)) |
|
||||
| [bb7c80477b](https://github.com/angular/angular/commit/bb7c80477b1258f48971b67b2eade6a4b41337f2) | fix | make parent injector argument required in `createEnvironmentInjector` ([#46397](https://github.com/angular/angular/pull/46397)) |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [82acbf919b](https://github.com/angular/angular/commit/82acbf919bae2ddb6a46f41239aa2a101901f089) | feat | improve error message for nullish header ([#46059](https://github.com/angular/angular/pull/46059)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [53ca936366](https://github.com/angular/angular/commit/53ca936366fb908278571bae5fcc7fa08b19a5a0) | feat | Add ability to create `UrlTree` from any `ActivatedRouteSnapshot` ([#45877](https://github.com/angular/angular/pull/45877)) |
|
||||
| [de058bba99](https://github.com/angular/angular/commit/de058bba9979f68de2320118b537e6be4dbb888d) | feat | Add CanMatch guard to control whether a Route should match ([#46021](https://github.com/angular/angular/pull/46021)) |
|
||||
| [6c1357dd7d](https://github.com/angular/angular/commit/6c1357dd7d5f466575398ebc32c581068d9bf2df) | feat | Add stable cancelation code to `NavigationCancel` event ([#46675](https://github.com/angular/angular/pull/46675)) |
|
||||
| [a4ce273e50](https://github.com/angular/angular/commit/a4ce273e50551e6c6bc8f3a86591b04760de7ba4) | feat | Add the target `RouterStateSnapshot` to `NavigationError` ([#46731](https://github.com/angular/angular/pull/46731)) |
|
||||
| [abe3759e24](https://github.com/angular/angular/commit/abe3759e2417c0396d75e226edcef2fae99e363b) | fix | allow to return `UrlTree` from `CanMatchFn` ([#46455](https://github.com/angular/angular/pull/46455)) |
|
||||
| [e8c7dd10e9](https://github.com/angular/angular/commit/e8c7dd10e93d338456131e11d600bf758ee48634) | fix | Ensure `APP_INITIALIZER` of `enabledBlocking` option completes ([#46026](https://github.com/angular/angular/pull/46026)) |
|
||||
| [ce20ed067f](https://github.com/angular/angular/commit/ce20ed067f12714ee6488ffe07f1a1c18bb60a15) | fix | Ensure Route injector is created before running CanMatch guards ([#46394](https://github.com/angular/angular/pull/46394)) |
|
||||
| [6a7b818d94](https://github.com/angular/angular/commit/6a7b818d94fdd13d81a01285e3e4be953a29cc06) | fix | Ensure target `RouterStateSnapshot` is defined in `NavigationError` ([#46842](https://github.com/angular/angular/pull/46842)) |
|
||||
| [f94c6f433d](https://github.com/angular/angular/commit/f94c6f433dba3924b79f137cfcc49d2dfd4d679c) | fix | Expose CanMatchFn as public API ([#46394](https://github.com/angular/angular/pull/46394)) |
|
||||
| [e8ae0fe3e9](https://github.com/angular/angular/commit/e8ae0fe3e91e2e805146fad0d2f0976b1f886112) | fix | Fix cancellation code for canLoad rejections ([#46752](https://github.com/angular/angular/pull/46752)) |
|
||||
### upgrade
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [e9cb0454dc](https://github.com/angular/angular/commit/e9cb0454dce2113cfd5ba11deeca6cdcf47d47f0) | feat | more closely align `UpgradeModule#bootstrap()` with `angular.bootstrap()` ([#46214](https://github.com/angular/angular/pull/46214)) |
|
||||
## Special Thanks
|
||||
AleksanderBodurri, Alex Rickabaugh, Andrew Kushnir, Andrew Scott, Cédric Exbrayat, Dmitrij Kuba, Dylan Hunn, George Kalpakas, Jessica Janiuk, JiaLiPassion, Joey Perrott, John Vandenberg, JoostK, Keith Li, Or'el Ben-Ya'ir, Paul Gschwendtner, Pawel Kozlowski, SyedAhm3r, arturovt, mariu, markostanimirovic and mgechev
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.0.6"></a>
|
||||
# 14.0.6 (2022-07-13)
|
||||
### compiler-cli
|
||||
@@ -18,33 +117,6 @@ Alan Agius, Andrew Scott, Bob Watson, Dylan Hunn, George Kalpakas, Ivaylo Kirov,
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.1.0-next.4"></a>
|
||||
# 14.1.0-next.4 (2022-07-06)
|
||||
## Deprecations
|
||||
### core
|
||||
- The bit field signature of `inject()` has been deprecated, in favor of the
|
||||
new options object. Correspondingly, `InjectFlags` is deprecated as well.
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [6f11a58040](https://github.com/angular/angular/commit/6f11a580406877e440c43df31fae3d5f120cafed) | feat | Add extended diagnostic to warn when text attributes are intended to be bindings ([#46161](https://github.com/angular/angular/pull/46161)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [96c6139c9a](https://github.com/angular/angular/commit/96c6139c9ab35aa6ab2330a5a79a5906d5c2e8be) | feat | add ability to set inputs on ComponentRef ([#46641](https://github.com/angular/angular/pull/46641)) |
|
||||
| [a7a14df5f8](https://github.com/angular/angular/commit/a7a14df5f8ff2d1e6a4dba3ac53f4479a6646810) | feat | introduce `EnvironmentInjector.runInContext` API ([#46653](https://github.com/angular/angular/pull/46653)) |
|
||||
| [fa52b6e906](https://github.com/angular/angular/commit/fa52b6e906e549e1c6b4a4f4428596d093fb0549) | feat | options object to supersede bit flags for `inject()` ([#46649](https://github.com/angular/angular/pull/46649)) |
|
||||
| [af20112222](https://github.com/angular/angular/commit/af20112222fcfa961ff9a2dee4050dd59aa4156e) | feat | support the descendants option for ContentChild queries ([#46638](https://github.com/angular/angular/pull/46638)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [6c1357dd7d](https://github.com/angular/angular/commit/6c1357dd7d5f466575398ebc32c581068d9bf2df) | feat | Add stable cancelation code to `NavigationCancel` event ([#46675](https://github.com/angular/angular/pull/46675)) |
|
||||
| [e8c7dd10e9](https://github.com/angular/angular/commit/e8c7dd10e93d338456131e11d600bf758ee48634) | fix | Ensure `APP_INITIALIZER` of `enabledBlocking` option completes ([#46026](https://github.com/angular/angular/pull/46026)) |
|
||||
## Special Thanks
|
||||
Alan Agius, Alex Rickabaugh, Andrew Scott, Aristeidis Bampakos, Bob Watson, George Kalpakas, Paul Gschwendtner and Pawel Kozlowski
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.0.5"></a>
|
||||
# 14.0.5 (2022-07-06)
|
||||
### router
|
||||
@@ -56,39 +128,6 @@ Alan Agius, Alex Rickabaugh, Andrew Kushnir, Andrew Scott, Aristeidis Bampakos,
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.1.0-next.3"></a>
|
||||
# 14.1.0-next.3 (2022-06-29)
|
||||
### animations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [4eb1ca11f0](https://github.com/angular/angular/commit/4eb1ca11f0fbc7683115fc382420b3e75f248b4c) | fix | cleanup DOM elements when the root view is removed ([#45143](https://github.com/angular/angular/pull/45143)) |
|
||||
| [b417370383](https://github.com/angular/angular/commit/b41737038377af480763226a904b67e7d8e283ae) | fix | enable shadowElements to leave when their parent does ([#46459](https://github.com/angular/angular/pull/46459)) |
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [4a2e7335b1](https://github.com/angular/angular/commit/4a2e7335b180190800cf2c5db8ed1c8841dbf473) | feat | make the `CommonModule` pipes standalone ([#46401](https://github.com/angular/angular/pull/46401)) |
|
||||
| [a7597dd080](https://github.com/angular/angular/commit/a7597dd08026a4071758323d54ccbfb382e0c780) | feat | make the CommonModule directives standalone ([#46469](https://github.com/angular/angular/pull/46469)) |
|
||||
| [1c39aace0e](https://github.com/angular/angular/commit/1c39aace0e74b02338729e5fb61e322ab06a9e14) | fix | handle CSS custom properties in NgStyle ([#46451](https://github.com/angular/angular/pull/46451)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8b6f4215a3](https://github.com/angular/angular/commit/8b6f4215a3c13a44d989d6068f6fb4625f3bab67) | fix | trigger `ApplicationRef.destroy` when Platform is destroyed ([#46497](https://github.com/angular/angular/pull/46497)) |
|
||||
| [606d94299a](https://github.com/angular/angular/commit/606d94299ac929243e8fa10fe7e00dee6d40064b) | fix | Update ngfor error code to be negative ([#46555](https://github.com/angular/angular/pull/46555)) |
|
||||
| [f86e0948f8](https://github.com/angular/angular/commit/f86e0948f80d398a8c4da9032372e083acc5d7a2) | fix | Updates error to use RuntimeError code ([#46526](https://github.com/angular/angular/pull/46526)) |
|
||||
### forms
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [0a5c8c0bc4](https://github.com/angular/angular/commit/0a5c8c0bc45ec58bcd297c7b001b88aec5c5e14d) | fix | Convert existing reactive errors to use RuntimeErrorCode. ([#46560](https://github.com/angular/angular/pull/46560)) |
|
||||
| [f6a096e3d4](https://github.com/angular/angular/commit/f6a096e3d4db9dfc31ab9228f37e119b87e5f8cf) | fix | Update a Forms validator error to use RuntimeError ([#46537](https://github.com/angular/angular/pull/46537)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [ee39cf62bc](https://github.com/angular/angular/commit/ee39cf62bc3f3d60d1dfe7064fe34565e5429b84) | fix | Ensure that new `RouterOutlet` instances work after old ones are destroyed ([#46554](https://github.com/angular/angular/pull/46554)) |
|
||||
## Special Thanks
|
||||
Alan Agius, Alex Rickabaugh, Andrew Kushnir, Andrew Scott, Bezael, Chad Ramos, Chellappan, Cédric Exbrayat, Dylan Hunn, George Kalpakas, Jeremy Meiss, Jessica Janiuk, Joey Perrott, KMathy, Kristiyan Kostadinov, Paul Gschwendtner, Pawel Kozlowski, Ramesh Thiruchelvam, Vaibhav Kumar, arturovt, dario-piotrowicz and renovate[bot]
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.0.4"></a>
|
||||
# 14.0.4 (2022-06-29)
|
||||
### animations
|
||||
@@ -120,37 +159,6 @@ Alan Agius, Alex Rickabaugh, Andrew Kushnir, Andrew Scott, Bezael, Chad Ramos, C
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.1.0-next.2"></a>
|
||||
# 14.1.0-next.2 (2022-06-22)
|
||||
### animations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [342effeb7d](https://github.com/angular/angular/commit/342effeb7d4d078ea51a7c345497794a7834b3c0) | fix | reset the start and done fns on player reset ([#46364](https://github.com/angular/angular/pull/46364)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [ddd6d66203](https://github.com/angular/angular/commit/ddd6d662038336f9a8e7d68a8b5cda2c3ca1c1d7) | fix | deduplicate imports of standalone components in JIT compiler ([#46439](https://github.com/angular/angular/pull/46439)) |
|
||||
| [3d8787c961](https://github.com/angular/angular/commit/3d8787c961176e15a7583d415f778054378ea06e) | fix | handle NgModules with standalone pipes in TestBed correctly ([#46407](https://github.com/angular/angular/pull/46407)) |
|
||||
| [bb7c80477b](https://github.com/angular/angular/commit/bb7c80477b1258f48971b67b2eade6a4b41337f2) | fix | make parent injector argument required in `createEnvironmentInjector` ([#46397](https://github.com/angular/angular/pull/46397)) |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [82acbf919b](https://github.com/angular/angular/commit/82acbf919bae2ddb6a46f41239aa2a101901f089) | feat | improve error message for nullish header ([#46059](https://github.com/angular/angular/pull/46059)) |
|
||||
### platform-server
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [08d3db232c](https://github.com/angular/angular/commit/08d3db232cb758701c41277996f1b41773f98e0d) | fix | invalid style attribute being generated for null values ([#46433](https://github.com/angular/angular/pull/46433)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [abe3759e24](https://github.com/angular/angular/commit/abe3759e2417c0396d75e226edcef2fae99e363b) | fix | allow to return `UrlTree` from `CanMatchFn` ([#46455](https://github.com/angular/angular/pull/46455)) |
|
||||
| [ce20ed067f](https://github.com/angular/angular/commit/ce20ed067f12714ee6488ffe07f1a1c18bb60a15) | fix | Ensure Route injector is created before running CanMatch guards ([#46394](https://github.com/angular/angular/pull/46394)) |
|
||||
| [f94c6f433d](https://github.com/angular/angular/commit/f94c6f433dba3924b79f137cfcc49d2dfd4d679c) | fix | Expose CanMatchFn as public API ([#46394](https://github.com/angular/angular/pull/46394)) |
|
||||
## Special Thanks
|
||||
4javier, Aakash, Alan Agius, Andrew Kushnir, Andrew Scott, Aristeidis Bampakos, Dany Paredes, Derek Cormier, Dmitrij Kuba, JoostK, Kristiyan Kostadinov, Paul Gschwendtner, Ramesh Thiruchelvam, arturovt, behrooz bozorg chami, dario-piotrowicz, markostanimirovic, renovate[bot] and web-dave
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.0.3"></a>
|
||||
# 14.0.3 (2022-06-22)
|
||||
### animations
|
||||
@@ -171,31 +179,6 @@ Alan Agius, Alex Rickabaugh, Andrew Kushnir, Andrew Scott, Bezael, Chad Ramos, C
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.1.0-next.1"></a>
|
||||
# 14.1.0-next.1 (2022-06-15)
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8b9c32d4dc](https://github.com/angular/angular/commit/8b9c32d4dccca5417adce1ca6067adf0805d6d08) | fix | allow null in ngComponentOutlet ([#46280](https://github.com/angular/angular/pull/46280)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [131d029da1](https://github.com/angular/angular/commit/131d029da16b7d486cdc200f00160b9a11871fb2) | feat | detect missing control flow directive imports in standalone components ([#46146](https://github.com/angular/angular/pull/46146)) |
|
||||
| [04acc6b14d](https://github.com/angular/angular/commit/04acc6b14d502597a98537019822f1a1217c9a61) | fix | don't emit empty providers array ([#46301](https://github.com/angular/angular/pull/46301)) |
|
||||
| [f35f4751b5](https://github.com/angular/angular/commit/f35f4751b54dcb9e65f2d72aeea87651314159e8) | fix | use inline type-check blocks for components outside `rootDir` ([#46096](https://github.com/angular/angular/pull/46096)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b1a3dec58d](https://github.com/angular/angular/commit/b1a3dec58d0dc21d76f757d4085c7581d89dc7dd) | fix | Resolve forwardRef declarations for jit ([#46334](https://github.com/angular/angular/pull/46334)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [de058bba99](https://github.com/angular/angular/commit/de058bba9979f68de2320118b537e6be4dbb888d) | feat | Add CanMatch guard to control whether a Route should match ([#46021](https://github.com/angular/angular/pull/46021)) |
|
||||
## Special Thanks
|
||||
Alex Rickabaugh, Andrew Kushnir, Andrew Scott, Badawi7, Daniel Schmitz, Derek Cormier, Jessica Janiuk, JiaLiPassion, JoostK, Kevin Davila, Kristiyan Kostadinov, Paul Draper, Paul Gschwendtner, Tom Eustace, Totati, Younes Jaaidi, alefra, dario-piotrowicz, markostanimirovic, mgechev, piyush132000, sten-bone and vivekkoya
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.0.2"></a>
|
||||
# 14.0.2 (2022-06-15)
|
||||
### common
|
||||
@@ -216,21 +199,6 @@ Alex Rickabaugh, Andrew Scott, Badawi7, Daniel Schmitz, Derek Cormier, JoostK, K
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.1.0-next.0"></a>
|
||||
# 14.1.0-next.0 (2022-06-08)
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [53ca936366](https://github.com/angular/angular/commit/53ca936366fb908278571bae5fcc7fa08b19a5a0) | feat | Add ability to create `UrlTree` from any `ActivatedRouteSnapshot` ([#45877](https://github.com/angular/angular/pull/45877)) |
|
||||
### upgrade
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [e9cb0454dc](https://github.com/angular/angular/commit/e9cb0454dce2113cfd5ba11deeca6cdcf47d47f0) | feat | more closely align `UpgradeModule#bootstrap()` with `angular.bootstrap()` ([#46214](https://github.com/angular/angular/pull/46214)) |
|
||||
## Special Thanks
|
||||
AleksanderBodurri, Alex Rickabaugh, Andrew Kushnir, Andrew Scott, George Kalpakas, Jessica Janiuk, Joey Perrott, Keith Li, SyedAhm3r, mariu and mgechev
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="14.0.1"></a>
|
||||
# 14.0.1 (2022-06-08)
|
||||
### bazel
|
||||
|
||||
@@ -123,7 +123,7 @@ load("@io_bazel_rules_webtesting//web:repositories.bzl", "web_test_repositories"
|
||||
|
||||
web_test_repositories()
|
||||
|
||||
load("@npm//@angular/dev-infra-private/bazel/browsers:browser_repositories.bzl", "browser_repositories")
|
||||
load("@npm//@angular/build-tooling/bazel/browsers:browser_repositories.bzl", "browser_repositories")
|
||||
|
||||
browser_repositories()
|
||||
|
||||
@@ -158,10 +158,10 @@ cldr_xml_data_repository(
|
||||
# sass rules
|
||||
http_archive(
|
||||
name = "io_bazel_rules_sass",
|
||||
sha256 = "2f86f221636cf721bd118ac954d0c982ef16cb3f795794ce17a5e0b7e62e103b",
|
||||
strip_prefix = "rules_sass-eda73f679f50d1d30599cebb8cc1bbc5ae43d5c6",
|
||||
sha256 = "85b34f2e5e227aa586b6e0fd6942262e17b3cface596891eeef5a29a0b7467e3",
|
||||
strip_prefix = "rules_sass-697e5a08bdd39aee49f2c6f4eb621ef59e677e49",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/rules_sass/archive/eda73f679f50d1d30599cebb8cc1bbc5ae43d5c6.zip",
|
||||
"https://github.com/bazelbuild/rules_sass/archive/697e5a08bdd39aee49f2c6f4eb621ef59e677e49.zip",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
@name `inject()` must be called from an injection context
|
||||
@category runtime
|
||||
@shortDescription `inject()` must be called from an injection context (a constructor, a factory function or a field initializer)
|
||||
@shortDescription `inject()` must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with `EnvironmentInjector#runInContext`.
|
||||
|
||||
@description
|
||||
You see this error when you try to use the `inject()` function outside of the allowed injection context. The injection context is available during the class creation and initialization.
|
||||
You see this error when you try to use the `inject()` function outside of the allowed injection context. The injection context is available during the class creation and initialization. It is also available to functions
|
||||
used with `EnvironmentInjector#runInContext`.
|
||||
|
||||
In practice the `inject()` calls are allowed in a constructor, a constructor parameter and a field initializer:
|
||||
|
||||
@@ -34,7 +35,7 @@ providers: [
|
||||
]
|
||||
```
|
||||
|
||||
Calls to the `inject()` function outside of the class creation context will result in error. Most notably, calls to `inject()` are disallowed after a class instance was created, in methods (including lifecycle hooks):
|
||||
Calls to the `inject()` function outside of the class creation or `runInContext` will result in error. Most notably, calls to `inject()` are disallowed after a class instance was created, in methods (including lifecycle hooks):
|
||||
|
||||
```typescript
|
||||
@Component({ ... })
|
||||
|
||||
-12
@@ -13,26 +13,18 @@ export abstract class Parent { abstract name: string; }
|
||||
|
||||
const DifferentParent = Parent;
|
||||
|
||||
// #docregion provide-parent, provide-the-parent
|
||||
// Helper method to provide the current component instance in the name of a `parentType`.
|
||||
// #enddocregion provide-the-parent
|
||||
// The `parentType` defaults to `Parent` when omitting the second parameter.
|
||||
// #docregion provide-the-parent
|
||||
export function provideParent
|
||||
// #enddocregion provide-the-parent
|
||||
(component: any, parentType?: any) {
|
||||
return { provide: parentType || Parent, useExisting: forwardRef(() => component) };
|
||||
}
|
||||
// #enddocregion provide-parent
|
||||
|
||||
// Simpler syntax version that always provides the component in the name of `Parent`.
|
||||
export function provideTheParent
|
||||
// #docregion provide-the-parent
|
||||
(component: any) {
|
||||
return { provide: Parent, useExisting: forwardRef(() => component) };
|
||||
}
|
||||
// #enddocregion provide-the-parent
|
||||
|
||||
|
||||
///////// C - Child //////////
|
||||
const templateC = `
|
||||
@@ -119,9 +111,7 @@ export class BobComponent implements Parent {
|
||||
@Component({
|
||||
selector: 'beth',
|
||||
template: templateB,
|
||||
// #docregion beth-providers
|
||||
providers: [ provideParent(BethComponent, DifferentParent) ]
|
||||
// #enddocregion beth-providers
|
||||
})
|
||||
export class BethComponent implements Parent {
|
||||
name = 'Beth';
|
||||
@@ -169,9 +159,7 @@ export class AlexComponent extends Base
|
||||
<bob></bob>
|
||||
<carol></carol>
|
||||
</div> `,
|
||||
// #docregion alice-providers
|
||||
providers: [ provideParent(AliceComponent) ]
|
||||
// #enddocregion alice-providers
|
||||
})
|
||||
// #docregion alice-class-signature
|
||||
export class AliceComponent implements Parent
|
||||
|
||||
@@ -7,7 +7,6 @@ import { InjectionToken } from '@angular/core';
|
||||
export const APP_CONFIG = new InjectionToken<AppConfig>('app.config');
|
||||
// #enddocregion token
|
||||
|
||||
// #docregion config
|
||||
export const HERO_DI_CONFIG: AppConfig = {
|
||||
apiEndpoint: 'api.heroes.com',
|
||||
title: 'Dependency Injection'
|
||||
|
||||
@@ -29,15 +29,11 @@ import { ProvidersModule } from './providers.module';
|
||||
InjectorComponent,
|
||||
TestComponent
|
||||
],
|
||||
// #docregion providers
|
||||
providers: [
|
||||
// #enddocregion providers
|
||||
Logger,
|
||||
// #docregion providers
|
||||
UserService,
|
||||
{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }
|
||||
],
|
||||
// #enddocregion providers
|
||||
exports: [ CarComponent, HeroesComponent ],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
|
||||
@@ -21,9 +21,7 @@ import { Logger } from './logger.service';
|
||||
export class InjectorComponent {
|
||||
car: Car;
|
||||
|
||||
// #docregion get-hero-service
|
||||
heroService: HeroService;
|
||||
// #enddocregion get-hero-service
|
||||
hero: Hero;
|
||||
|
||||
constructor(private injector: Injector) {
|
||||
|
||||
@@ -154,7 +154,6 @@ export class Provider6bComponent {
|
||||
|
||||
//////////////////////////////////////////
|
||||
|
||||
// #docregion silent-logger
|
||||
// An object in the shape of the logger service
|
||||
function silentLoggerFn() {}
|
||||
|
||||
@@ -162,15 +161,12 @@ export const SilentLogger = {
|
||||
logs: ['Silent logger says "Shhhhh!". Provided via "useValue"'],
|
||||
log: silentLoggerFn
|
||||
};
|
||||
// #enddocregion silent-logger
|
||||
|
||||
@Component({
|
||||
selector: 'provider-7',
|
||||
template,
|
||||
providers:
|
||||
// #docregion providers-7
|
||||
[{ provide: Logger, useValue: SilentLogger }]
|
||||
// #enddocregion providers-7
|
||||
})
|
||||
export class Provider7Component {
|
||||
log: string;
|
||||
|
||||
@@ -7,6 +7,5 @@ import { Component } from '@angular/core';
|
||||
})
|
||||
export class CartComponent {
|
||||
|
||||
constructor() { }
|
||||
|
||||
}
|
||||
|
||||
+2
-11
@@ -1,11 +1,6 @@
|
||||
// #docplaster
|
||||
/*
|
||||
// #docregion as-generated
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
// #enddocregion as-generated
|
||||
*/
|
||||
// #docregion imports
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Product } from '../products';
|
||||
// #enddocregion imports
|
||||
// #docregion as-generated
|
||||
@@ -16,14 +11,10 @@ import { Product } from '../products';
|
||||
styleUrls: ['./product-alerts.component.css']
|
||||
})
|
||||
// #docregion input-decorator
|
||||
export class ProductAlertsComponent implements OnInit {
|
||||
export class ProductAlertsComponent {
|
||||
|
||||
// #enddocregion as-generated
|
||||
@Input() product!: Product;
|
||||
// #docregion as-generated
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,6 @@ nav a:hover {
|
||||
color: white;
|
||||
background-color: #42545C;
|
||||
}
|
||||
nav a.active {
|
||||
nav a:active {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ In the following example, the `HeroListComponent` class includes:
|
||||
* A `selectedHero` property that holds the last hero selected by the user.
|
||||
* A `selectHero()` method sets a `selectedHero` property when the user clicks to choose a hero from that list.
|
||||
|
||||
The component initializes the `heroes` property by using the `HeroService` service, which is a TypeScript [parameter property](https://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties) on the constructor. Angular's dependency injection system provides the `HeroService` service to the component.
|
||||
The component initializes the `heroes` property by using the `HeroService` service, which is a TypeScript [parameter property](https://www.typescriptlang.org/docs/handbook/2/classes.html#parameter-properties) on the constructor. Angular's dependency injection system provides the `HeroService` service to the component.
|
||||
|
||||
<code-example header="src/app/hero-list.component.ts (class)" path="architecture/src/app/hero-list.component.ts" region="class"></code-example>
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ import * as Plotly from 'plotly.js-dist-min';
|
||||
class AppComponent implements OnInit {
|
||||
constructor(private ngZone: NgZone) {}
|
||||
ngOnInit() {
|
||||
this.zone.runOutsideAngular(() => {
|
||||
this.ngZone.runOutsideAngular(() => {
|
||||
Plotly.newPlot('chart', data);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ The `CountdownLocalVarParentComponent` that hosts the timer component is as foll
|
||||
|
||||
The parent component cannot data bind to the child's `start` and `stop` methods nor to its `seconds` property.
|
||||
|
||||
Place a local variable, `#timer`, on the tag `<countdown-timer>` representing the child component.
|
||||
Place a local variable, `#timer`, on the tag `<app-countdown-timer>` representing the child component.
|
||||
That gives you a reference to the child component and the ability to access *any of its properties or methods* from within the parent template.
|
||||
|
||||
This example wires parent buttons to the child's `start` and `stop` and uses interpolation to display the child's `seconds` property.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Content Contributor's Guide
|
||||
# Documentation contributor's guide
|
||||
|
||||
Angular, as an open source project, depends on its community. This dependence is particularly important to the documentation. The more the community contributes to the documentation, the better the documentation becomes, which helps both new and experienced Angular developers.
|
||||
|
||||
@@ -6,9 +6,9 @@ The topics in this section cover ways in which you can contribute to the Angular
|
||||
|
||||
## Before you begin
|
||||
|
||||
Before you get started with your contributions, we recommend that you review [Contributing to Angular](https://github.com/angular/angular/blob/main/CONTRIBUTING.md). That topic explains many of the tasks and guidelines you need to know before you make your first pull request.
|
||||
Before you get started with your contributions, review [Contributing to Angular](https://github.com/angular/angular/blob/main/CONTRIBUTING.md). That topic explains many of the tasks and guidelines you need to know before you make your first pull request.
|
||||
|
||||
## Contributing to Angular
|
||||
## Contributing to Angular documentation
|
||||
|
||||
<div class="card-container">
|
||||
<a href="guide/reviewing-content" class="docs-card" title="Reviewing content">
|
||||
@@ -37,3 +37,4 @@ Before you get started with your contributions, we recommend that you review [Co
|
||||
<p class="card-footer">Localize documentation</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# Creating an injectable service
|
||||
|
||||
Service is a broad category encompassing any value, function, or feature that an application needs. A service is typically a class with a narrow, well-defined purpose. A component is one type of class that can use DI.
|
||||
|
||||
Angular distinguishes components from services to increase modularity and reusability. By separating a component's view-related features from other kinds of processing, you can make your component classes lean and efficient.
|
||||
|
||||
Ideally, a component's job is to enable the user experience and nothing more. A component should present properties and methods for data binding, 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. By defining such processing tasks in an injectable service class, you make those tasks available to any component. You can also make your application more adaptable by injecting different providers of the same kind of service, as appropriate in different circumstances.
|
||||
|
||||
Angular does not enforce these principles. Angular helps you follow these principles by making it easy to factor your application logic into services and make those services available to components through DI.
|
||||
|
||||
## Service examples
|
||||
|
||||
Here's an example of a service class that logs to the browser console.
|
||||
|
||||
<code-example header="src/app/logger.service.ts (class)" path="architecture/src/app/logger.service.ts" 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 header="src/app/hero.service.ts (class)" path="architecture/src/app/hero.service.ts" region="class"></code-example>
|
||||
|
||||
## Creating an injectable service
|
||||
|
||||
Angular CLI provides a command to create a new service. In the following example, you add a new service to your application, which was created earlier with the `ng new` command.
|
||||
|
||||
To generate a new `HeroService` class in the `src/app/heroes` folder, follow these steps:
|
||||
|
||||
1. Run this [Angular CLI](cli) command:
|
||||
|
||||
<code-example language="sh">
|
||||
ng generate service heroes/hero
|
||||
</code-example>
|
||||
|
||||
This command creates the following default `HeroService`.
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" header="src/app/heroes/hero.service.ts (CLI-generated)">
|
||||
</code-example>
|
||||
|
||||
The `@Injectable()` decorator specifies that Angular can use this class in the DI system.
|
||||
The metadata, `providedIn: 'root'`, means that the `HeroService` is visible throughout the application.
|
||||
|
||||
2. Add a `getHeroes()` method that returns the heroes from `mock.heroes.ts` to get the hero mock data:
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.3.ts" header="src/app/heroes/hero.service.ts">
|
||||
</code-example>
|
||||
|
||||
For clarity and maintainability, it is recommended that you define components and services in separate files.
|
||||
|
||||
## Injecting services
|
||||
|
||||
To inject a service as a dependency into a component, you can use component's `constructor()` and supply a constructor argument with the dependency type. The following example specifies the `HeroService` in the `HeroListComponent` constructor. The type of the `heroService` is `HeroService`. Angular recognizes the `HeroService` as a dependency, since that class was previously annotated with the `@Injectable` decorator.
|
||||
|
||||
<code-example header="src/app/heroes/hero-list.component (constructor signature)" path="dependency-injection/src/app/heroes/hero-list.component.ts"
|
||||
region="ctor-signature">
|
||||
</code-example>
|
||||
|
||||
## Injecting services in other services
|
||||
|
||||
When a service depends on another service, follow the same pattern as injecting into a component.
|
||||
In the following example `HeroService` depends on a `Logger` service to report its activities.
|
||||
|
||||
First, import the `Logger` service. Next, inject the `Logger` service in the `HeroService` `constructor()` by specifying `private logger: Logger`.
|
||||
|
||||
Here, the `constructor()` specifies a type of `Logger` and stores the instance of `Logger` in a private field called `logger`.
|
||||
|
||||
The following code tabs feature the `Logger` service and two versions of `HeroService`. The first version of `HeroService` does not depend on the `Logger` service. The revised second version does depend on `Logger` service.
|
||||
|
||||
<code-tabs>
|
||||
|
||||
<code-pane header="src/app/heroes/hero.service (v2)" path="dependency-injection/src/app/heroes/hero.service.2.ts">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/heroes/hero.service (v1)" path="dependency-injection/src/app/heroes/hero.service.1.ts">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/logger.service"
|
||||
path="dependency-injection/src/app/logger.service.ts">
|
||||
</code-pane>
|
||||
|
||||
</code-tabs>
|
||||
|
||||
In this example, the `getHeroes()` method uses the `Logger` service by logging a message when fetching heroes.
|
||||
|
||||
## What's next
|
||||
|
||||
* [How to configure dependencies in DI](guide/dependency-injection-providers)
|
||||
* [How to use `InjectionTokens` to provide and inject values other than services/classes](guide/dependency-injection-providers#configuring-dependency-providers)
|
||||
* [Dependency Injection in Action](guide/dependency-injection-in-action)
|
||||
|
||||
@reviewed 2022-08-02
|
||||
@@ -213,7 +213,7 @@ It's visually simple: a few properties and the logs produced by a logger.
|
||||
</div>
|
||||
|
||||
The code behind it customizes how and where the DI framework provides dependencies.
|
||||
The use cases illustrate different ways to use the [*provide* object literal](guide/dependency-injection-providers#provide) to associate a definition object with a DI token.
|
||||
The use cases illustrate different ways to use the *provide* object literal to associate a definition object with a DI token.
|
||||
|
||||
<code-example header="hero-of-the-month.component.ts" path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="hero-of-the-month"></code-example>
|
||||
|
||||
@@ -389,8 +389,10 @@ But they did neither.
|
||||
|
||||
When you use a class this way, it's called a *class interface*.
|
||||
|
||||
As mentioned in [DI Providers](guide/dependency-injection-providers#di-and-interfaces), an interface is not a valid DI token because it is a TypeScript artifact that doesn't exist at run time.
|
||||
Use this abstract class interface to get the strong typing of an interface, and also use it as a provider token in the way you would a normal class.
|
||||
As mentioned in [Configuring dependency providers](guide/dependency-injection-providers),
|
||||
an interface is not a valid DI token because it is a TypeScript artifact that doesn't exist at run time.
|
||||
Use this abstract class interface to get the strong typing of an interface,
|
||||
and also use it as a provider token in the way you would a normal class.
|
||||
|
||||
A class interface should define *only* the members that its consumers are allowed to call.
|
||||
Such a narrowing interface helps decouple the concrete class from its consumers.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Dependency injection in Angular
|
||||
|
||||
When you develop a smaller part of your system, like a module or a class, you may need to use features from other classes. For example, you may need an HTTP service to make backend calls. Dependency Injection, or DI, is a design pattern and mechanism for creating and delivering some parts of an application to other parts of an application that require them. Angular supports this design pattern and you can use it in your applications to increase flexibility and modularity.
|
||||
|
||||
In Angular, dependencies are typically services, but they also can be values, such as strings or functions. An injector for an application (created automatically during bootstrap) instantiates dependencies when needed, using a configured provider of the service or value.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
See the <live-example></live-example> for a working example containing the code snippets in this guide.
|
||||
|
||||
</div>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You should be familiar with the Angular apps in general, and have the fundamental knowledge of Components, Directives, and NgModules. It's highly recommended that you complete the following tutorial:
|
||||
|
||||
[Tour of Heroes application and tutorial](tutorial)
|
||||
|
||||
## Learn about Angular dependency injection
|
||||
|
||||
<div class="card-container">
|
||||
<a href="guide/dependency-injection" class="docs-card" title="Understanding dependency injection">
|
||||
<section>Understanding dependency injection</section>
|
||||
<p>Learn basic principles of dependency injection in Angular.</p>
|
||||
<p class="card-footer">Understanding dependency injection</p>
|
||||
</a>
|
||||
<a href="guide/creating-injectable-service" class="docs-card" title="Creating and injecting service">
|
||||
<section>Creating and injecting service</section>
|
||||
<p>Describes how to create a service and inject it in other services and components.</p>
|
||||
<p class="card-footer">Creating an injectable service</p>
|
||||
</a>
|
||||
<a href="guide/dependency-injection-providers" class="docs-card" title="Configuring dependency providers">
|
||||
<section>Configuring dependency providers</section>
|
||||
<p>Describes how to configure dependencies using the providers field on the @Component and @NgModule decorators. Also describes how to use InjectionToken to provide and inject values in DI, which can be helpful when you want to use a value other than classes as dependencies.</p>
|
||||
<p class="card-footer">Configuring dependency providers</p>
|
||||
</a>
|
||||
<a href="guide/hierarchical-dependency-injection" class="docs-card" title="Hierarchical injectors">
|
||||
<section>Hierarchical injectors</section>
|
||||
<p>Hierarchical DI enables you to share dependencies between different parts of the application only when and if you need to. This is an advanced topic.</p>
|
||||
<p class="card-footer">Hierarchical injectors</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@reviewed 2022-08-02
|
||||
@@ -1,179 +1,116 @@
|
||||
# Dependency providers
|
||||
# Configuring dependency providers
|
||||
|
||||
By configuring providers, you can make services available to the parts of your application that need them.
|
||||
|
||||
A dependency [provider](guide/glossary#provider) configures an injector with a [DI token](guide/glossary#di-token), which that injector uses to provide the runtime version of a dependency value.
|
||||
The Creating and injecting services topic describes how to use classes as dependencies. Besides classes, you can also use other values such as Boolean, string, date, and objects as dependencies. Angular DI provides the necessary APIs to make the dependency configuration flexible, so you can make those values available in DI.
|
||||
|
||||
## Specifying a provider token
|
||||
|
||||
If you specify the service class as the provider token, the default behavior is for the injector to instantiate that class with `new`.
|
||||
If you specify the service class as the provider token, the default behavior is for the injector to instantiate that class using the `new` operator.
|
||||
|
||||
In the following example, the `Logger` class provides a `Logger` instance.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-logger"></code-example>
|
||||
|
||||
You can, however, configure an injector with an alternative provider to deliver some other object that provides the needed logging functionality.
|
||||
You can, however, configure a DI to use a different class or any other different value to associate with the `Logger` class. So when the `Logger` is injected, this new value is used instead.
|
||||
|
||||
Configure an injector with a service class, and provide a substitute class, an object, or a factory function.
|
||||
In fact, the class provider syntax is a shorthand expression that expands into a provider configuration, defined by the `Provider` interface.
|
||||
|
||||
<a id="token"></a>
|
||||
<a id="injection-token"></a>
|
||||
|
||||
## Dependency injection tokens
|
||||
|
||||
When you configure an [injector](guide/glossary#injector) with a [provider](guide/glossary#provider), you are associating that provider with a [dependency injection token](guide/glossary#di-token), or DI token.
|
||||
The injector lets Angular create a map of any internal dependencies.
|
||||
The DI token acts as a key to that map.
|
||||
|
||||
The dependency value is an instance, and the class type serves as a lookup key.
|
||||
Here, the injector uses the `HeroService` type as the token for looking up `heroService`.
|
||||
|
||||
<code-example header="src/app/injector.component.ts" path="dependency-injection/src/app/injector.component.ts" region="get-hero-service"></code-example>
|
||||
|
||||
When you define a constructor parameter with the `HeroService` class type, Angular knows to inject the service associated with that `HeroService` class token:
|
||||
|
||||
<code-example header="src/app/heroes/hero-list.component.ts" path="dependency-injection/src/app/heroes/hero-list.component.ts" region="ctor-signature"></code-example>
|
||||
|
||||
Though classes provide many dependency values, the expanded `provide` object lets you associate different kinds of providers with a DI token.
|
||||
|
||||
<a id="provide"></a>
|
||||
|
||||
## Defining providers
|
||||
|
||||
The class provider syntax is a shorthand expression that expands into a provider configuration, defined by the [`Provider` interface](api/core/Provider).
|
||||
The following example is the class provider syntax for providing a `Logger` class in the `providers` array.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-logger"></code-example>
|
||||
|
||||
Angular expands the `providers` value into a full provider object as follows.
|
||||
Angular expands the `providers` value in this case into a full provider object as follows:
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-3" ></code-example>
|
||||
|
||||
The expanded provider configuration is an object literal with two properties:
|
||||
- The `provide` property holds the token that serves as the key for both locating a dependency value and configuring the injector.
|
||||
- The second property is a provider definition object, which tells the injector how to create the dependency value. The provider-definition key can be one of the following:
|
||||
- useClass - this option tells Angular DI to instantiate a provided class when a dependency is injected
|
||||
- useExisting - allows you to alias a token and reference any existing one.
|
||||
- useFactory - allows you to define a function that constructs a dependency.
|
||||
- useValue - provides a static value that should be used as a dependency.
|
||||
|
||||
* The `provide` property holds the [token](#token) that serves as the key for both locating a dependency value and configuring the injector.
|
||||
The section below describes how to use the mentioned provider definition keys.
|
||||
|
||||
* The second property is a provider definition object, which tells the injector how to create the dependency value.
|
||||
The provider-definition key can be `useClass`, as in the example.
|
||||
It can also be `useExisting`, `useValue`, or `useFactory`.
|
||||
Each of these keys provides a different type of dependency, as discussed in the following section.
|
||||
<a id="token"></a>
|
||||
<a id="injection-token"></a>
|
||||
|
||||
<a id="class-provider"></a>
|
||||
|
||||
## Specifying an alternative class provider
|
||||
|
||||
Different classes can provide the same service.
|
||||
For example, the following code tells the injector to return a `BetterLogger` instance when the component asks for a logger using the `Logger` token.
|
||||
### Class providers: useClass
|
||||
The `useClass` provider key lets you create and return a new instance of the specified class.
|
||||
You can use this type of provider to substitute an alternative implementation for a common or default class. The alternative implementation can, for example, implement a different strategy, extend the default class, or emulate the behavior of the real class in a test case.
|
||||
In the following example, the `BetterLogger` class would be instantiated when the `Logger` dependency is requested in a component or any other class.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-4" ></code-example>
|
||||
|
||||
<a id="class-provider-dependencies"></a>
|
||||
|
||||
### Configuring class providers with dependencies
|
||||
|
||||
If the alternative class providers have their own dependencies, specify both providers in the `providers` metadata property of the parent module or component.
|
||||
If the alternative class providers have their own dependencies, specify both providers in the providers metadata property of the parent module or component.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-5"></code-example>
|
||||
|
||||
In this example, `EvenBetterLogger` displays the user name in the log message.
|
||||
This logger gets the user from an injected `UserService` instance.
|
||||
In this example, `EvenBetterLogger` displays 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"></code-example>
|
||||
|
||||
The injector needs providers for both this new logging service and its dependent `UserService`.
|
||||
Angular DI knows how to construct the `UserService` dependency, since it has been configured above and is available in the injector.
|
||||
|
||||
<a id="aliased-class-providers"></a>
|
||||
### Alias providers: useExisting
|
||||
|
||||
### Aliasing class providers
|
||||
The `useExisting` provider key lets you map one token to another. In effect, the first token is an alias for the service associated with the second token, creating two ways to access the same service object.
|
||||
|
||||
To alias a class provider, specify the alias and the class provider in the `providers` array with the `useExisting` property.
|
||||
|
||||
In the following example, the injector injects the singleton instance of `NewLogger` when the component asks for either the new or the old logger.
|
||||
In this way, `OldLogger` is an alias for `NewLogger`.
|
||||
In the following example, the injector injects the singleton instance of `NewLogger` when the component asks for either the new or the old logger. In this way, `OldLogger` is an alias for `NewLogger`.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6b"></code-example>
|
||||
|
||||
Be sure you don't alias `OldLogger` to `NewLogger` with `useClass`, as this creates two different `NewLogger` instances.
|
||||
Ensure you do not alias `OldLogger` to `NewLogger` with `useClass`, as this creates two different `NewLogger` instances.
|
||||
|
||||
<a id="provideparent"></a>
|
||||
### Factory providers: useFactory
|
||||
The `useFactory` provider key lets you create a dependency object by calling a factory function. With this approach you can create a dynamic value based on information available in the DI and elsewhere in the app.
|
||||
|
||||
## Aliasing a class interface
|
||||
In the following example, only authorized users should see secret heroes in the `HeroService`.
|
||||
Authorization can change during the course of a single application session, as when a different user logs in .
|
||||
|
||||
Generally, writing variations of the same parent alias provider uses [forwardRef](guide/dependency-injection-in-action#forwardref) as follows.
|
||||
To keep security-sensitive information in `UserService` and out of `HeroService`, give the `HeroService` constructor a boolean flag to control display of secret heroes.
|
||||
|
||||
<code-example header="dependency-injection-in-action/src/app/parent-finder.component.ts" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers"></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>
|
||||
|
||||
To streamline your code, extract that logic into a helper function using the `provideParent()` helper function.
|
||||
To implement the `isAuthorized` flag, use a factory provider to create a new logger instance for `HeroService`.
|
||||
|
||||
<code-example header="dependency-injection-in-action/src/app/parent-finder.component.ts" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-the-parent"></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>
|
||||
|
||||
Now you can add a parent provider to your components that's easier to read and understand.
|
||||
The factory function has access to `UserService`.
|
||||
You inject both `Logger` and `UserService` into the factory provider so the injector can pass them along to the factory function.
|
||||
|
||||
<code-example header="dependency-injection-in-action/src/app/parent-finder.component.ts" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-providers"></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>
|
||||
|
||||
### Aliasing multiple class interfaces
|
||||
* The `useFactory` field specifies that the provider is a factory function whose implementation is `heroServiceFactory`.
|
||||
|
||||
To alias multiple parent types, each with its own class interface token, configure `provideParent()` to accept more arguments.
|
||||
* The `deps` property is an array of provider tokens.
|
||||
The `Logger` and `UserService` classes serve as tokens for their own class providers.
|
||||
The injector resolves these tokens and injects the corresponding services into the matching `heroServiceFactory` factory function parameters.
|
||||
|
||||
Here's a revised version that defaults to `parent` but also accepts an optional second parameter for a different parent class interface.
|
||||
Capturing the factory provider in the exported variable, `heroServiceProvider`, makes the factory provider reusable.
|
||||
|
||||
<code-example header="dependency-injection-in-action/src/app/parent-finder.component.ts" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-parent"></code-example>
|
||||
### Value providers: useValue
|
||||
|
||||
Next, to use `provideParent()` with a different parent type, provide a second argument, here `DifferentParent`.
|
||||
The `useValue` key lets you associate a fixed value with a DI token. Use this technique to provide runtime configuration constants such as website base addresses and feature flags. You can also use a value provider in a unit test to provide mock data in place of a production data service. The next section provides more information about the `useValue` key.
|
||||
|
||||
<code-example header="dependency-injection-in-action/src/app/parent-finder.component.ts" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="beth-providers"></code-example>
|
||||
## Using an `InjectionToken` object
|
||||
|
||||
<a id="value-provider"></a>
|
||||
Define and use an `InjectionToken` object for choosing a provider token for non-class dependencies. The following example defines a token, `APP_CONFIG` of the type `InjectionToken`.
|
||||
|
||||
## Injecting an object
|
||||
|
||||
To inject an object, configure the injector with the `useValue` option.
|
||||
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"></code-example>
|
||||
|
||||
In this example, `SilentLogger` is an object that fulfills the logger role.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="silent-logger"></code-example>
|
||||
|
||||
<a id="non-class-dependencies"></a>
|
||||
|
||||
### Injecting a configuration object
|
||||
|
||||
A common use case for object literals is a configuration object.
|
||||
The following configuration object includes the title of the application and the address of a web API endpoint.
|
||||
|
||||
<code-example header="src/app/app.config.ts (excerpt)" path="dependency-injection/src/app/app.config.ts" region="config"></code-example>
|
||||
|
||||
To provide and inject the configuration object, specify the object in the `@NgModule()` `providers` array.
|
||||
|
||||
<code-example header="src/app/app.module.ts (providers)" path="dependency-injection/src/app/app.module.ts" region="providers"></code-example>
|
||||
|
||||
<a id="injectiontoken"></a>
|
||||
|
||||
### Using an `InjectionToken` object
|
||||
|
||||
Define and use an `InjectionToken` object for choosing a provider token for non-class dependencies.
|
||||
The following example defines a token, `APP_CONFIG` of the type `InjectionToken`.
|
||||
|
||||
<code-example header="src/app/app.config.ts" path="dependency-injection/src/app/app.config.ts" region="token"></code-example>
|
||||
<code-example path="dependency-injection/src/app/app.config.ts" region="token" header="src/app/app.config.ts"></code-example>
|
||||
|
||||
The optional type parameter, `<AppConfig>`, and the token description, `app.config`, specify the token's purpose.
|
||||
|
||||
Next, register the dependency provider in the component using the `InjectionToken` object of `APP_CONFIG`.
|
||||
|
||||
<code-example header="src/app/providers.component.ts" path="dependency-injection/src/app/providers.component.ts" region="providers-9"></code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" header="src/app/providers.component.ts" region="providers-9"></code-example>
|
||||
|
||||
Now, inject the configuration object into the constructor with `@Inject()` parameter decorator.
|
||||
|
||||
<code-example header="src/app/app.component.ts" path="dependency-injection/src/app/app.component.2.ts" region="ctor"></code-example>
|
||||
<code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" header="src/app/app.component.ts"></code-example>
|
||||
|
||||
<a id="di-and-interfaces"></a>
|
||||
### Interfaces and DI
|
||||
|
||||
#### Interfaces and dependency injection
|
||||
|
||||
Though the TypeScript `AppConfig` interface supports typing within the class, the `AppConfig` interface plays no role in dependency injection.
|
||||
In TypeScript, an interface is a design-time artifact, and doesn't have a runtime representation, or token, that the DI framework can use.
|
||||
Though the TypeScript `AppConfig` interface supports typing within the class, the `AppConfig` interface plays no role in DI.
|
||||
In TypeScript, an interface is a design-time artifact, and does not have a runtime representation, or token, that the DI framework can use.
|
||||
|
||||
When the transpiler changes TypeScript to JavaScript, the interface disappears because JavaScript doesn't have interfaces.
|
||||
|
||||
@@ -183,47 +120,9 @@ Because there is no interface for Angular to find at runtime, the interface cann
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-9-ctor-interface"></code-example>
|
||||
|
||||
<a id="factory-provider"></a>
|
||||
<a id="factory-providers"></a>
|
||||
|
||||
## Using factory providers
|
||||
## What's next
|
||||
|
||||
To create a changeable, dependent value based on information unavailable before run time, use a factory provider.
|
||||
* [Dependency Injection in Action](guide/dependency-injection-in-action)
|
||||
|
||||
In the following example, only authorized users should see secret heroes in the `HeroService`.
|
||||
Authorization can change during the course of a single application session, as when a different user logs in .
|
||||
|
||||
To keep security-sensitive information in `UserService` and out of `HeroService`, give the `HeroService` constructor a boolean flag to control display of secret heroes.
|
||||
|
||||
<code-example header="src/app/heroes/hero.service.ts (excerpt)" path="dependency-injection/src/app/heroes/hero.service.ts" region="internals"></code-example>
|
||||
|
||||
To implement the `isAuthorized` flag, use a factory provider to create a new logger instance for `HeroService`.
|
||||
|
||||
<code-example header="src/app/heroes/hero.service.provider.ts (excerpt)" path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="factory"></code-example>
|
||||
|
||||
The factory function has access to `UserService`.
|
||||
You inject both `Logger` and `UserService` into the factory provider so the injector can pass them along to the factory function.
|
||||
|
||||
<code-example header="src/app/heroes/hero.service.provider.ts (excerpt)" path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="provider"></code-example>
|
||||
|
||||
* The `useFactory` field specifies that the provider is a factory function whose implementation is `heroServiceFactory`
|
||||
* The `deps` property is an array of [provider tokens](#token).
|
||||
The `Logger` and `UserService` classes serve as tokens for their own class providers.
|
||||
The injector resolves these tokens and injects the corresponding services into the matching `heroServiceFactory` factory function parameters.
|
||||
|
||||
Capturing the factory provider in the exported variable, `heroServiceProvider`, makes the factory provider reusable.
|
||||
|
||||
The following side-by-side example shows how `heroServiceProvider` replaces `HeroService` in the `providers` array.
|
||||
|
||||
<code-tabs>
|
||||
<code-pane header="src/app/heroes/heroes.component (v3)" path="dependency-injection/src/app/heroes/heroes.component.ts"></code-pane>
|
||||
<code-pane header="src/app/heroes/heroes.component (v2)" path="dependency-injection/src/app/heroes/heroes.component.1.ts"></code-pane>
|
||||
</code-tabs>
|
||||
|
||||
<!-- links -->
|
||||
|
||||
<!-- external links -->
|
||||
|
||||
<!-- end links -->
|
||||
|
||||
@reviewed 2022-02-28
|
||||
@reviewed 2022-08-02
|
||||
@@ -1,94 +1,84 @@
|
||||
# Dependency injection in Angular
|
||||
# Understanding dependency injection
|
||||
|
||||
Dependencies are services or objects that a class needs to perform its function.
|
||||
Dependency injection, or DI, is a design pattern in which a class requests dependencies from external sources rather than creating them.
|
||||
Dependency injection, or DI, is one of the fundamental concepts in Angular. DI is wired into the Angular framework and allows classes with Angular decorators, such as Components, Directives, Pipes, and Injectables, to configure dependencies that they need.
|
||||
|
||||
Angular's DI framework provides dependencies to a class upon instantiation.
|
||||
Use Angular DI to increase flexibility and modularity in your applications.
|
||||
Two main roles exist in the DI system: dependency consumer and dependency provider.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
Angular facilitates the interaction between dependency consumers and dependency providers using an abstraction called [Injector](guide/glossary#injector). When a dependency is requested, the injector checks its registry to see if there is an instance already available there. If not, a new instance is created and stored in the registry. Angular creates an application-wide injector (also known as "root" injector) during the application bootstrap process, as well as any other injectors as needed. In most cases you don't need to manually create injectors, but you should know that there is a layer that connects providers and consumers.
|
||||
|
||||
See the <live-example></live-example> for a working example containing the code snippets in this guide.
|
||||
This topic covers basic scenarios of how a class can act as a dependency. Angular also allows you to use functions, objects, primitive types such as string or Boolean, or any other types as dependencies. For more information, see [Dependency providers](guide/dependency-injection-providers).
|
||||
|
||||
</div>
|
||||
## Providing dependency
|
||||
|
||||
## Creating an injectable service
|
||||
Imagine there is a class called HeroService that needs to act as a dependency in a component.
|
||||
|
||||
To create a new `HeroService` class in the `src/app/heroes` directory, use the following command.
|
||||
|
||||
<code-example format="shell" header="Generate the heroes/hero service" language="shell">
|
||||
|
||||
ng generate service heroes/hero
|
||||
The first step is to add the @Injectable decorator to show that the class can be injected.
|
||||
|
||||
<code-example language="typescript">
|
||||
@Injectable()
|
||||
class HeroService {}
|
||||
</code-example>
|
||||
|
||||
This command creates the following default `HeroService`.
|
||||
The next step is to make it available in the DI by providing it. A dependency can be provided in multiple places:
|
||||
|
||||
<code-example header="src/app/heroes/hero.service.ts (CLI-generated)" path="dependency-injection/src/app/heroes/hero.service.0.ts"></code-example>
|
||||
* At the Component level, using the `providers` field of the `@Component` decorator. In this case the `HeroService` becomes available to all instances of this component and other components and directives used in the template. For example:
|
||||
|
||||
The `@Injectable()` decorator specifies that Angular can use this class in the DI system.
|
||||
The metadata, `providedIn: 'root'`, means that the `HeroService` is visible throughout the application.
|
||||
<code-example language="typescript">
|
||||
@Component({
|
||||
selector: 'hero-list',
|
||||
template: '...',
|
||||
providers: [HeroService]
|
||||
})
|
||||
class HeroListComponent {}
|
||||
</code-example>
|
||||
|
||||
Next, to get the hero mock data, add a `getHeroes()` method that returns the heroes from `mock.heroes.ts`.
|
||||
When you register a provider at the component level, you get a new instance of the service with each new instance of that component.
|
||||
|
||||
<code-example header="src/app/heroes/hero.service.ts" path="dependency-injection/src/app/heroes/hero.service.3.ts"></code-example>
|
||||
* At the NgModule level, using the `providers` field of the `@NgModule` decorator. In this scenario, the `HeroService` is available to all components, directives and pipes declared in this NgModule. For example:
|
||||
|
||||
For clarity and maintainability, it is recommended that you define components and services in separate files.
|
||||
<code-example language="typescript">
|
||||
@NgModule({
|
||||
declarations: [HeroListComponent]
|
||||
providers: [HeroService]
|
||||
})
|
||||
class HeroListModule {}
|
||||
</code-example>
|
||||
|
||||
If you do combine a component and service in the same file, it is important to define the service first, and then the component.
|
||||
If you define the component before the service, Angular returns a run-time null reference error.
|
||||
When you register a provider with a specific NgModule, the same instance of a service is available to all components in that NgModule.
|
||||
|
||||
<a id="injector-config"></a>
|
||||
<a id="bootstrap"></a>
|
||||
* At the application root level, which allows injecting it into other classes in the application. This can be done by adding the `providedIn: 'root'` field to the `@Injectable` decorator:
|
||||
|
||||
## Injecting services
|
||||
<code-example language="typescript">
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
class HeroService {}
|
||||
</code-example>
|
||||
|
||||
Injecting services lets a component access their features and data.
|
||||
When you provide the service at the root level, Angular creates a single, shared instance of the `HeroService` 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 application if it isn't used, a process known as tree-shaking.
|
||||
|
||||
To inject a dependency in a component's `constructor()`, supply a constructor argument with the dependency type.
|
||||
The following example specifies the `HeroService` in the `HeroListComponent` constructor.
|
||||
The type of `heroService` is `HeroService`.
|
||||
## Providing dependency
|
||||
|
||||
<code-example header="src/app/heroes/hero-list.component (constructor signature)" path="dependency-injection/src/app/heroes/hero-list.component.ts"
|
||||
region="ctor-signature"></code-example>
|
||||
The most common way to inject a dependency is to declare it in a class constructor. When Angular creates a new instance of a component, directive, or pipe class, it determines which services or other dependencies that class needs by looking at the constructor parameter types. For example, if the `HeroListComponent` needs the `HeroService`, the constructor can look like this:
|
||||
|
||||
For more information, see [Providing dependencies in modules](guide/providers) and [Hierarchical injectors](guide/hierarchical-dependency-injection).
|
||||
<code-example language="typescript">
|
||||
@Component({ … })
|
||||
class HeroListComponent {
|
||||
constructor(private service: HeroService) {}
|
||||
}
|
||||
</code-example>
|
||||
|
||||
<a id="service-needs-service"></a>
|
||||
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 creates one using the registered provider, and adds it to the injector before returning the service to Angular.
|
||||
|
||||
## Using services in other services
|
||||
When all requested services have been resolved and returned, Angular can call the component's constructor with those services as arguments.
|
||||
|
||||
When a service depends on another service, follow the same pattern as injecting into a component.
|
||||
In the following example `HeroService` depends on a `Logger` service to report its activities.
|
||||
|
||||
First, import the `Logger` service.
|
||||
Next, inject the `Logger` service in the `HeroService` `constructor()` by specifying `private logger: Logger` within the parentheses.
|
||||
|
||||
When you create a class whose `constructor()` has parameters, specify the type and metadata about those parameters so that Angular can inject the correct service.
|
||||
|
||||
Here, `constructor()` specifies a type of `Logger` and stores the instance of `Logger` in a private field called `logger`.
|
||||
|
||||
The following code tabs feature the `Logger` service and two versions of `HeroService`.
|
||||
`HeroService (v2)` depends on `Logger` service, while `HeroService (v1)` doesn't depend on the `Logger` service.
|
||||
|
||||
<code-tabs>
|
||||
<code-pane header="src/app/heroes/hero.service (v2)" path="dependency-injection/src/app/heroes/hero.service.2.ts"></code-pane>
|
||||
<code-pane header="src/app/heroes/hero.service (v1)" path="dependency-injection/src/app/heroes/hero.service.1.ts"></code-pane>
|
||||
<code-pane header="src/app/logger.service" path="dependency-injection/src/app/logger.service.ts"></code-pane>
|
||||
</code-tabs>
|
||||
|
||||
In this example, the `getHeroes()` method uses the `Logger` service by logging a message when fetching heroes.
|
||||
<div class="lightbox">
|
||||
<img src="generated/images/guide/architecture/injector-injects.png" alt="Service" class="left">
|
||||
</div>
|
||||
|
||||
## What's next
|
||||
|
||||
* [Dependency providers](guide/dependency-injection-providers)
|
||||
* [DI tokens and providers](guide/dependency-injection-providers)
|
||||
* [Dependency Injection in Action](guide/dependency-injection-in-action)
|
||||
* [Creating and injecting services](guide/creating-injectable-service)
|
||||
* [Dependency Injection in Action](guide/dependency-injection-in-action)
|
||||
|
||||
<!-- links -->
|
||||
|
||||
<!-- external links -->
|
||||
|
||||
<!-- end links -->
|
||||
|
||||
@reviewed 2022-02-28
|
||||
@reviewed 2022-08-02
|
||||
|
||||
@@ -76,6 +76,8 @@ v14 - v17
|
||||
| `@angular/core/testing` | [`async`](#testing) | <!-- v9 --> v12 |
|
||||
| `@angular/forms` | [`FormBuilder.group` legacy options parameter](api/forms/FormBuilder#group) | <!-- v11 --> v14 |
|
||||
| `@angular/platform-server` | [`renderModuleFactory`](#platform-server) | <!-- v13 --> v15 |
|
||||
| `@angular/platform-server` | [`ServerTransferStateModule`](#platform-server) | <!-- v14 --> v16 |
|
||||
| `@angular/platform-browser` | [`BrowserTransferStateModule`](#platform-browser) | <!-- v14 --> v16 |
|
||||
| `@angular/router` | [`relativeLinkResolution`](#relativeLinkResolution) | <!-- v14 --> v16 |
|
||||
| `@angular/router` | [`resolver` argument in `RouterOutletContract.activateWith`](#router) | <!-- v14 --> v16 |
|
||||
| `@angular/router` | [`resolver` field of the `OutletContext` class](#router) | <!-- v14 --> v16 |
|
||||
@@ -159,6 +161,15 @@ In the [API reference section](api) of this site, deprecated APIs are indicated
|
||||
| [`resolver` field of the `OutletContext` class](api/router/OutletContext#resolver) | No replacement needed | v14 | Component factories are not required to create an instance of a component dynamically. Passing a factory resolver via `resolver` class field is no longer needed. |
|
||||
|
||||
|
||||
<a id="platform-browser"></a>
|
||||
|
||||
### @angular/platform-browser
|
||||
|
||||
| API | Replacement | Deprecation announced | Details |
|
||||
|:--- |:--- |:--- |:--- |
|
||||
| [`BrowserTransferStateModule`](api/platform-browser/BrowserTransferStateModule) | No replacement needed. | v14.1 | The `TransferState` class is available for injection without importing additional modules on the client side of a server-rendered application. |
|
||||
|
||||
|
||||
<a id="platform-browser-dynamic"></a>
|
||||
|
||||
### @angular/platform-browser-dynamic
|
||||
@@ -175,6 +186,8 @@ In the [API reference section](api) of this site, deprecated APIs are indicated
|
||||
| API | Replacement | Deprecation announced | Details |
|
||||
|:--- |:--- |:--- |:--- |
|
||||
| [`renderModuleFactory`](api/platform-server/renderModuleFactory) | [`renderModule`](api/platform-server/renderModule) | v13 | This symbol is no longer necessary. See [JIT API changes due to ViewEngine deprecation](#jit-api-changes) for additional context. |
|
||||
| [`ServerTransferStateModule`](api/platform-server/ServerTransferStateModule) | No replacement needed. | v14.1 | The `TransferState` class is available for injection without importing additional modules during server side rendering, when `ServerModule` is imported or `renderApplication` function is used for bootstrap. |
|
||||
|
||||
|
||||
<a id="forms"></a>
|
||||
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
# Resolving documentation linter messages
|
||||
|
||||
This topic describes different ways to resolve common messages that the documentation linter produces.
|
||||
|
||||
## Anatomy of a documentation linter message
|
||||
|
||||
This is an example of a message produced by the documentation linter.
|
||||
|
||||
<div class="lightbox">
|
||||
|
||||
<img alt="sample of a lint message" src="generated/images/guide/docs-lint-errors/sample-lint-error.png">
|
||||
|
||||
</div>
|
||||
|
||||
A documentation linter message contains these elements. Starting from the top line:
|
||||
|
||||
<!-- vale Angular.Angular_Spelling = NO -->
|
||||
<!-- vale Angular.Google_Spacing = NO -->
|
||||
<!-- vale Angular.Google_We = NO -->
|
||||
|
||||
* The severity. One of these icons indicates the message's severity:
|
||||
* <img alt="documentation style error icon" src="generated/images/guide/docs-lint-errors/lint-error-icon.png"> **Error** (A red `x` in a circle) Errors must be corrected before the file can be merged.
|
||||
* <img alt="documentation style warning icon" src="generated/images/guide/docs-lint-errors/lint-warn-icon.png"> **Warning** (A yellow exclamation mark in a triangle) Warnings should be corrected before the file is merged.
|
||||
* <img alt="documentation style info icon" src="generated/images/guide/docs-lint-errors/lint-info-icon.png"> **Info** (A blue lower-case `i` in a circle) Informational messages should be corrected before the file is merged.
|
||||
* The style rule message. The style rule message in this example is: *Did you really mean 'sdfdsfsdfdfssd'? It wasn't found in our dictionary.*
|
||||
* The style reference. Some references are linked to a style guide topic that explains the rule. The style reference in this example is: *Vale(Angular.Angular_Spelling)*.
|
||||
* The location of the problem text in the document identified by source line and column as precisely as possible. Some messages might not have the exact location of the text that triggered the message. The location in this example is: *[Ln 8, Col 1]*.
|
||||
* The style test definition file that produced the message, which is linked to the file. The style test definition in this example is: *Angular_Spelling.yml[Ln 1, Col 1]: View rule*.
|
||||
|
||||
<!-- vale Angular.Google_We = YES -->
|
||||
<!-- vale Angular.Google_Spacing = YES -->
|
||||
<!-- vale Angular.Angular_Spelling = YES -->
|
||||
|
||||
## Strategies to improve your documentation
|
||||
|
||||
These tips can help you improve your documentation and remove documentation linter messages.
|
||||
|
||||
### Refer to the style guides
|
||||
|
||||
The lint tool tests against the styles found in these style guides.
|
||||
Most style tests include links to relevant sections in these documents for more information.
|
||||
|
||||
* [Angular documentation style guide][AioGuideDocsStyleGuide]
|
||||
* [Google Developer Documentation Style Guide][GoogleDevelopersStyle]
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Not every style mentioned in the style guides has a test.
|
||||
Style guides and the style tests can change.
|
||||
|
||||
</div>
|
||||
|
||||
### Split up long sentences
|
||||
|
||||
Generally, shorter sentences are easier to read than longer ones.
|
||||
Long sentences can occur when you try to say too much at once.
|
||||
Long sentences, as well as the use of parentheses, semi-colons, or words identified as *too-wordy*, generally require rethinking and rewriting.
|
||||
|
||||
Consider restructuring a long sentence to break its individual ideas into distinct sentences or bullet points.
|
||||
|
||||
### Use lists and tables
|
||||
|
||||
Sentences that contain comma-separated lists might be clearer if presented as a bulleted-list or table.
|
||||
|
||||
Consider changing a comma-separated list of items in a sentence to a list of bullets to make those list items easier to read.
|
||||
|
||||
### Use more common words
|
||||
|
||||
Shorter, more common words are generally easier to read than longer ones.
|
||||
This does not mean you need to write down to the audience. Technical docs should still be precise.
|
||||
Angular docs are read by many people around the world and should use language that the most people can understand.
|
||||
|
||||
If you think a specific term is required even though it is been flagged as uncommon, try to include a short explanation of the term.
|
||||
Also, try adding some context around its first mention.
|
||||
|
||||
Linking a term to another section or topic is also an option, but consider the disruption that causes to the reader before you use it.
|
||||
If you force a reader to go to another page for a definition, they might lose their concentration on the current topic and their primary goal.
|
||||
|
||||
### Use fewer words
|
||||
|
||||
If you can remove a word and not lose the meaning of the sentence, leave it out.
|
||||
|
||||
One common place where removing words can help is in a list of examples with more than two or three items.
|
||||
Before you place the items in a bullet list, consider if only one of the items can convey the desired meaning.
|
||||
Another option might be to replace a list of items with a single term that describes all the elements in your list.
|
||||
|
||||
## More about specific documentation linter messages
|
||||
|
||||
Most documentation linter messages are self-explanatory and include a link to supplementary documentation.
|
||||
Some messages identify areas in that the documentation might need more thought.
|
||||
The following types of messages often occur in areas of the text that should be reconsidered and rewritten to improve the text and remove the message.
|
||||
|
||||
### A word is *too-wordy* or should be replaced by another
|
||||
|
||||
Generally, technical documentation should use a simple and consistent vocabulary to be understood by a wide audience. Words that trigger this message are usually words for which there's a simpler way to convey the same thought.
|
||||
|
||||
<!-- vale Angular.Google_Spacing = NO -->
|
||||
<!-- vale Angular.Google_Headings = NO -->
|
||||
<!-- vale Angular.Google_Ellipses = NO -->
|
||||
<!-- vale Angular.WriteGood_TooWordy = NO -->
|
||||
|
||||
<!-- markdownlint-disable-file MD026 -->
|
||||
|
||||
#### Angular.WriteGood_TooWordy - See if you can rewrite the sentence...
|
||||
|
||||
<!-- vale Angular.WriteGood_TooWordy = YES -->
|
||||
<!-- vale Angular.Google_Ellipses = YES -->
|
||||
<!-- vale Angular.Google_Headings = YES -->
|
||||
<!-- vale Angular.Google_Spacing = YES -->
|
||||
|
||||
Words identified by this style test can usually be replaced by simpler words.
|
||||
If not, sentences with these words should be revised to use simpler language and avoid the word in the message.
|
||||
|
||||
The following table has some common words detected by this type of message and simpler words to try in their place.
|
||||
|
||||
<!-- vale Angular.WriteGood_TooWordy = NO -->
|
||||
|
||||
| *Too-wordy* word | Simpler replacement |
|
||||
|:-- |:-- |
|
||||
|accelerate |speed up |
|
||||
|accomplish |perform, finish |
|
||||
|acquire |get |
|
||||
|additional |more |
|
||||
|adjustment |change |
|
||||
|advantageous |beneficial |
|
||||
|consequently |as a result |
|
||||
|designate |assign |
|
||||
|equivalent |the same |
|
||||
|exclusively |only |
|
||||
|for the most part |generally |
|
||||
|have a tendency to |tend to |
|
||||
|in addition |furthermore |
|
||||
|modify |change or update |
|
||||
|monitor |observe |
|
||||
|necessitate |require |
|
||||
|one particular |one |
|
||||
|point in time |moment |
|
||||
|portion |part |
|
||||
|similar to |like |
|
||||
|validate |verify |
|
||||
|whether or not |whether |
|
||||
|
||||
<!-- vale Angular.WriteGood_TooWordy = YES -->
|
||||
|
||||
<!-- vale Angular.Google_Headings = NO -->
|
||||
|
||||
#### *WordList* messages
|
||||
|
||||
<!-- vale Angular.Google_Headings = YES -->
|
||||
|
||||
The messages about words detected by these style tests generally suggest a better alternative.
|
||||
While the word you used would probably be understood, it most likely triggered this message for one of the following reasons:
|
||||
|
||||
* The suggested works better in a screen-reader context.
|
||||
* The word that you used could produce an unpleasant response in the reader.
|
||||
* The suggested word is simpler, shorter, or easier for more people to understand.
|
||||
* The word you used has other possible variations. The suggested word is the variation to use in the documentation to be consistent.
|
||||
|
||||
<!-- vale Angular.Angular_Spelling = NO -->
|
||||
|
||||
### *Proselint* messages
|
||||
|
||||
The Proselint style tests test for words that are jargon or that could be offensive to some people.
|
||||
|
||||
<!-- vale Angular.Angular_Spelling = YES -->
|
||||
|
||||
Rewrite the text to replace the jargon or offensive language with more inclusive language.
|
||||
|
||||
### *Starting a sentence* messages
|
||||
|
||||
Some words, such as *so* and *there is/are*, aren't necessary at the beginning of a sentence.
|
||||
Sentences that start with the words identified by this message can usually be made shorter, simpler, and clearer by rewriting them without those openings.
|
||||
|
||||
### Cliches
|
||||
|
||||
Cliches should be replaced by more literal text.
|
||||
|
||||
Cliches make it difficult for people who don't understand English to understand the documentation. When cliches are translated by online tools such as Google translate, they can produce confusing results.
|
||||
|
||||
## If all else fails
|
||||
|
||||
The style rules generally guide you in the direction of clearer content, but sometimes you might need to break the rules.
|
||||
If you decide that the best choice for the text conflicts with the linter, mark the text as an exception to linting.
|
||||
|
||||
The documentation linter checks only the content that is rendered as text. It does not test code-formatted text. One common source of false problems is code references that are not formatted as code.
|
||||
|
||||
If you use these exceptions, please limit the amount of text that you exclude from analysis to the fewest lines possible.
|
||||
|
||||
When necessary, you can apply these exceptions to your content.
|
||||
|
||||
1. **General exception**
|
||||
|
||||
A *general exception* allows you to exclude the specified text from all lint testing.
|
||||
|
||||
To apply a general exception, surround the text that you do not want the linter to test with the HTML
|
||||
`comment` elements shown in this example.
|
||||
|
||||
```html
|
||||
|
||||
<!-- vale off -->
|
||||
|
||||
Text the linter does not check for any style problem.
|
||||
|
||||
<!-- vale on -->
|
||||
|
||||
```
|
||||
|
||||
Be sure to leave a blank line before and after each comment.
|
||||
|
||||
2. **Style exception**
|
||||
|
||||
A *style exception* allows you to exclude text from an individual style test.
|
||||
|
||||
To apply a style exception, surround the text that you do not want the linter to test with these HTML
|
||||
`comment` elements. Between these comments, the linter ignores the style test in the comment, but
|
||||
still tests for all other styles that are in use.
|
||||
|
||||
```html
|
||||
<!-- vale Style.Rule = NO -->
|
||||
<!-- vale Style.Rule = YES -->
|
||||
```
|
||||
|
||||
Replace `Style.Rule` in the comments with the style rule reference from the problem message displayed in the IDE.
|
||||
For example, imagine that you got this problem message and you want to use the word it identified as a problem.
|
||||
|
||||
```html
|
||||
Did you really mean 'inlines'? It was not found in our dictionary. Vale(Angular.Angular_Spelling) [Ln 24, Col 59]
|
||||
Angular_Spelling.yml[Ln 1, Col 1]: View rule
|
||||
```
|
||||
|
||||
The `Style.Rule` for this message is the text inside the parentheses: `Angular.Angular_Spelling` in this case.
|
||||
To turn off that style test, use the comments shown in this example.
|
||||
|
||||
```html
|
||||
|
||||
<!-- vale Angular.Angular_Spelling = NO -->
|
||||
|
||||
'inlines' does not display a problem because this text is not spell-checked.
|
||||
Remember that the linter does not check any spelling in this block of text.
|
||||
The linter continues to test all other style rules.
|
||||
|
||||
<!-- vale Angular.Angular_Spelling = YES -->
|
||||
|
||||
```
|
||||
|
||||
<!-- links -->
|
||||
|
||||
[AioGuideDocsStyleGuide]: https://angular.io/guide/docs-style-guide "Angular documentation style guide | Angular"
|
||||
|
||||
<!-- external links -->
|
||||
|
||||
[GoogleDevelopersStyle]: https://developers.google.com/style "About this guide | Google developer documentation style guide | Google Developers"
|
||||
|
||||
<!-- end links -->
|
||||
|
||||
<!-- @reviewed 2022-07-15 -->
|
||||
@@ -162,7 +162,7 @@ The following figure shows the final form.
|
||||
|
||||
| Steps | Details |
|
||||
|:--- |:--- |
|
||||
| Different types of forms and control collection | This tutorial shows how to build a questionaire, which is just one kind of dynamic form. The example uses `FormGroup` to collect a set of controls. For an example of a different type of dynamic form, see the section [Creating dynamic forms](guide/reactive-forms#creating-dynamic-forms "Create dynamic forms with arrays") in the Reactive Forms guide. That example also shows how to use `FormArray` instead of `FormGroup` to collect a set of controls. |
|
||||
| Different types of forms and control collection | This tutorial shows how to build a questionnaire, which is just one kind of dynamic form. The example uses `FormGroup` to collect a set of controls. For an example of a different type of dynamic form, see the section [Creating dynamic forms](guide/reactive-forms#creating-dynamic-forms "Create dynamic forms with arrays") in the Reactive Forms guide. That example also shows how to use `FormArray` instead of `FormGroup` to collect a set of controls. |
|
||||
| Validating user input | The section [Validating form input](guide/reactive-forms#validating-form-input "Basic input validation") introduces the basics of how input validation works in reactive forms. <br /> The [Form validation guide](guide/form-validation "Form validation guide") covers the topic in more depth. |
|
||||
|
||||
<!-- links -->
|
||||
|
||||
@@ -21,7 +21,19 @@ This topic uses the following pictographs.
|
||||
|
||||
</div>
|
||||
|
||||
## Two injector hierarchies
|
||||
The applications you build with Angular can become quite large, and one way to manage this complexity is to split up the application into many small well encapsulated modules, that are by themselves split up into a well-defined tree of components.
|
||||
The applications you build with Angular can become quite large, and one way to manage this complexity is to split up the application into many small well-encapsulated modules, that are by themselves split up into a well-defined tree of components.
|
||||
|
||||
There can be sections of your page that works in a completely independent way than the rest of the application, with its own local copies of the services and other dependencies that it needs. Some of the services that these sections of the application use might be shared with other parts of the application, or with parent components that are further up in the component tree, while other dependencies are meant to be private.
|
||||
|
||||
With hierarchical dependency injection, you can isolate sections of the application and give them their own private dependencies not shared with the rest of the application, or have parent components share certain dependencies with its child components only but not with the rest of the component tree, and so on. Hierarchical dependency injection enables you to share dependencies between different parts of the application only when and if you need to.
|
||||
|
||||
## Types of injector hierarchies
|
||||
|
||||
Injectors in Angular have rules that you can leverage to
|
||||
achieve the desired visibility of injectables in your applications.
|
||||
By understanding these rules, you can determine in which
|
||||
NgModule, Component, or Directive you should declare a provider.
|
||||
|
||||
Angular has two injector hierarchies:
|
||||
|
||||
@@ -173,7 +185,7 @@ If the component's injector lacks the provider, it passes the request up to its
|
||||
|
||||
The requests keep forwarding up until Angular finds an injector that can handle the request or runs out of ancestor `ElementInjector` hierarchies.
|
||||
|
||||
If Angular doesn't find the provider in any `ElementInjector` hierarchiess, it goes back to the element where the request originated and looks in the `ModuleInjector` hierarchy.
|
||||
If Angular doesn't find the provider in any `ElementInjector` hierarchies, it goes back to the element where the request originated and looks in the `ModuleInjector` hierarchy.
|
||||
If Angular still doesn't find the provider, it 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 resolve the dependency.
|
||||
@@ -454,7 +466,7 @@ Emoji from FlowerService: 🌻
|
||||
|
||||
</code-example>
|
||||
|
||||
In the logical tree, this would be represented as follows:
|
||||
In the logical tree, this is represented as follows:
|
||||
|
||||
<code-example format="html" language="html">
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ For example, you would use a pipe to show a date as **April 15, 1988** rather th
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
For the sample application used in this topic, see the <live-example></live-example>.
|
||||
For the sample application used in this topic, see the <live-example name="pipes"></live-example>.
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -63,11 +63,11 @@ This means that any services listed in their provider arrays aren't available be
|
||||
When the Angular router lazy-loads a module, it creates a new injector.
|
||||
This injector is a child of the root application injector.
|
||||
Imagine a tree of injectors; there is a single root injector and then a child injector for each lazy loaded module.
|
||||
The router adds all of the providers from the root injector to the child injector.
|
||||
When the router creates a component within the lazy-loaded context, Angular prefers service instances created from these providers to the service instances of the application root injector.
|
||||
This child injector gets populated with all the module-specific providers, if any.
|
||||
Look up resolution for every provider follows the [rules of dependency injection hierarchy](guide/hierarchical-dependency-injection#resolution-rules).
|
||||
|
||||
Any component created within a lazy loaded module's context, such as by router navigation, gets the local instance of the service, not the instance in the root application injector.
|
||||
Components in external modules continue to receive the instance created for the application root.
|
||||
Any component created within a lazy loaded module's context, such as by router navigation, gets its own local instance of child provided services, not the instance in the root application injector.
|
||||
Components in external modules continue to receive the instances created for the application root injector.
|
||||
|
||||
Though you can provide services by lazy loading modules, not all services can be lazy loaded.
|
||||
For instance, some modules only work in the root module, such as the Router.
|
||||
|
||||
@@ -2382,12 +2382,12 @@ Currently, the `AdminModule` does not preload because `CanLoad` is blocking it.
|
||||
|
||||
<a id="preload-canload"></a>
|
||||
|
||||
#### `CanLoad` blocks preload
|
||||
#### `CanLoad` blocks preload of children
|
||||
|
||||
The `PreloadAllModules` strategy does not load feature areas protected by a [CanLoad](#can-load-guard) guard.
|
||||
|
||||
You added a `CanLoad` guard to the route in the `AdminModule` a few steps back to block loading of that module until the user is authorized.
|
||||
That `CanLoad` guard takes precedence over the preload strategy.
|
||||
That `CanLoad` guard takes precedence over the preload strategy for loading children routes.
|
||||
|
||||
If you want to preload a module as well as guard against unauthorized access, remove the `canLoad()` guard method and rely on the [canActivate()](#can-activate-guard) guard alone.
|
||||
|
||||
|
||||
@@ -463,7 +463,7 @@ The link parameters array affords the flexibility to represent any routing depth
|
||||
|
||||
When the router navigates to a new component view, it updates the browser's location and history with a URL for that view.
|
||||
|
||||
Modern HTML5 browsers support [history.pushState](https://developer.mozilla.org/docs/Web/API/History_API/Working_with_the_History_API#adding_and_modifying_history_entries title="HTML5 browser history push-state"), a technique that changes a browser's location and history without triggering a server page request.
|
||||
Modern HTML5 browsers support [history.pushState](https://developer.mozilla.org/docs/Web/API/History_API/Working_with_the_History_API#adding_and_modifying_history_entries "HTML5 browser history push-state"), a technique that changes a browser's location and history without triggering a server page request.
|
||||
The router can compose a "natural" URL that is indistinguishable from one that would otherwise require a page load.
|
||||
|
||||
Here's the Crisis Center URL in this "HTML5 pushState" style:
|
||||
@@ -496,7 +496,7 @@ You also have the option of switching to the `HashLocationStrategy` with an over
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
For more information on providers and the bootstrap process, see [Dependency Injection](guide/dependency-injection#bootstrap).
|
||||
For more information on providers and the bootstrap process, see [Dependency Injection](guide/dependency-injection-providers).
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ The following template binds the value of `htmlSnippet`, once by interpolating i
|
||||
Interpolated content is always escaped —the HTML isn't interpreted and the browser displays angle brackets in the element's text content.
|
||||
|
||||
For the HTML to be interpreted, bind it to an HTML property such as `innerHTML`.
|
||||
But binding a value that an attacker might control into `innerHTML` normally causes an XSS vulnerability
|
||||
But binding a value that an attacker might control into `innerHTML` normally causes an XSS vulnerability.
|
||||
For example, one could execute JavaScript in a following way:
|
||||
|
||||
<code-example header="src/app/inner-html-binding.component.ts (class)" path="security/src/app/inner-html-binding.component.ts" region="class"></code-example>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
# Service worker configuration
|
||||
|
||||
This topic describes the properties of the service worker configuration file.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
A basic understanding of the following:
|
||||
|
||||
* [Service worker overview](https://developer.chrome.com/docs/workbox/service-worker-overview/)
|
||||
* [Service Worker in Production](guide/service-worker-devops)
|
||||
|
||||
The `ngsw-config.json` configuration file specifies which files and data URLs the Angular service worker should cache and how it should update the cached files and data.
|
||||
@@ -64,9 +67,11 @@ Example patterns:
|
||||
| `/*.html` | Specifies only HTML files in the root |
|
||||
| `!/**/*.map` | Exclude all sourcemaps |
|
||||
|
||||
## Service worker configuration properties
|
||||
|
||||
The following sections describe each property of the configuration file.
|
||||
|
||||
## `appData`
|
||||
### `appData`
|
||||
|
||||
This section enables you to pass any data you want that describes this particular version of the application.
|
||||
The `SwUpdate` service includes that data in the update notifications.
|
||||
@@ -74,12 +79,12 @@ Many applications use this section to provide additional information for the dis
|
||||
|
||||
<a id="index-file"></a>
|
||||
|
||||
## `index`
|
||||
### `index`
|
||||
|
||||
Specifies the file that serves as the index page to satisfy navigation requests.
|
||||
Usually this is `/index.html`.
|
||||
|
||||
## `assetGroups`
|
||||
### `assetGroups`
|
||||
|
||||
*Assets* are resources that are part of the application version that update along with the application.
|
||||
They can include resources loaded from the page's origin as well as third-party resources loaded from CDNs and other external URLs.
|
||||
@@ -134,12 +139,14 @@ interface AssetGroup {
|
||||
|
||||
</code-example>
|
||||
|
||||
### `name`
|
||||
Each `AssetGroup` is defined by the following asset group properties.
|
||||
|
||||
#### `name`
|
||||
|
||||
A `name` is mandatory.
|
||||
It identifies this particular group of assets between versions of the configuration.
|
||||
|
||||
### `installMode`
|
||||
#### `installMode`
|
||||
|
||||
The `installMode` determines how these resources are initially cached.
|
||||
The `installMode` can be either of two values:
|
||||
@@ -151,7 +158,7 @@ The `installMode` can be either of two values:
|
||||
|
||||
Defaults to `prefetch`.
|
||||
|
||||
### `updateMode`
|
||||
#### `updateMode`
|
||||
|
||||
For resources already in the cache, the `updateMode` determines the caching behavior when a new version of the application is discovered.
|
||||
Any resources in the group that have changed since the previous version are updated in accordance with `updateMode`.
|
||||
@@ -163,7 +170,7 @@ Any resources in the group that have changed since the previous version are upda
|
||||
|
||||
Defaults to the value `installMode` is set to.
|
||||
|
||||
### `resources`
|
||||
#### `resources`
|
||||
|
||||
This section describes the resources to cache, broken up into the following groups:
|
||||
|
||||
@@ -172,7 +179,7 @@ This section describes the resources to cache, broken up into the following grou
|
||||
| `files` | Lists patterns that match files in the distribution directory. These can be single files or glob-like patterns that match a number of files. |
|
||||
| `urls` | Includes both URLs and URL patterns that are matched at runtime. These resources are not fetched directly and do not have content hashes, but they are cached according to their HTTP headers. This is most useful for CDNs such as the Google Fonts service. <br /> *\(Negative glob patterns are not supported and `?` will be matched literally; that is, it will not match any character other than `?`.\)* |
|
||||
|
||||
### `cacheQueryOptions`
|
||||
#### `cacheQueryOptions`
|
||||
|
||||
These options are used to modify the matching behavior of requests.
|
||||
They are passed to the browsers `Cache#match` function.
|
||||
@@ -183,7 +190,7 @@ Currently, only the following options are supported:
|
||||
|:--- |:--- |
|
||||
| `ignoreSearch` | Ignore query parameters. Defaults to `false`. |
|
||||
|
||||
## `dataGroups`
|
||||
### `dataGroups`
|
||||
|
||||
Unlike asset resources, data requests are not versioned along with the application.
|
||||
They're cached according to manually-configured policies that are more useful for situations such as API requests and other data dependencies.
|
||||
@@ -236,11 +243,13 @@ export interface DataGroup {
|
||||
|
||||
</code-example>
|
||||
|
||||
### `name`
|
||||
Each `DataGroup` is defined by the following data group properties.
|
||||
|
||||
#### `name`
|
||||
|
||||
Similar to `assetGroups`, every data group has a `name` which uniquely identifies it.
|
||||
|
||||
### `urls`
|
||||
#### `urls`
|
||||
|
||||
A list of URL patterns.
|
||||
URLs that match these patterns are cached according to this data group's policy.
|
||||
@@ -249,7 +258,7 @@ Only non-mutating requests \(GET and HEAD\) are cached.
|
||||
* Negative glob patterns are not supported
|
||||
* `?` is matched literally; that is, it matches *only* the character `?`
|
||||
|
||||
### `version`
|
||||
#### `version`
|
||||
|
||||
Occasionally APIs change formats in a way that is not backward-compatible.
|
||||
A new version of the application might not be compatible with the old API format and thus might not be compatible with existing cached resources from that API.
|
||||
@@ -258,18 +267,22 @@ A new version of the application might not be compatible with the old API format
|
||||
|
||||
`version` is an integer field and defaults to `1`.
|
||||
|
||||
### `cacheConfig`
|
||||
#### `cacheConfig`
|
||||
|
||||
This section defines the policy by which matching requests are cached.
|
||||
The following properties define the policy by which matching requests are cached.
|
||||
|
||||
#### `maxSize`
|
||||
##### `maxSize`
|
||||
|
||||
\(required\) The maximum number of entries, or responses, in the cache.
|
||||
**Required**
|
||||
|
||||
The maximum number of entries, or responses, in the cache.
|
||||
Open-ended caches can grow in unbounded ways and eventually exceed storage quotas, calling for eviction.
|
||||
|
||||
#### `maxAge`
|
||||
##### `maxAge`
|
||||
|
||||
(required) The `maxAge` parameter indicates how long responses are allowed to remain in the cache before being considered invalid and evicted.
|
||||
**Required**
|
||||
|
||||
The `maxAge` parameter indicates how long responses are allowed to remain in the cache before being considered invalid and evicted.
|
||||
`maxAge` is a duration string, using the following unit suffixes:
|
||||
|
||||
| Suffixes | Details |
|
||||
@@ -282,7 +295,7 @@ Open-ended caches can grow in unbounded ways and eventually exceed storage quota
|
||||
|
||||
For example, the string `3d12h` caches content for up to three and a half days.
|
||||
|
||||
#### `timeout`
|
||||
##### `timeout`
|
||||
|
||||
This duration string specifies the network timeout.
|
||||
The network timeout is how long the Angular service worker waits for the network to respond before using a cached response, if configured to do so.
|
||||
@@ -298,7 +311,7 @@ The network timeout is how long the Angular service worker waits for the network
|
||||
|
||||
For example, the string `5s30u` translates to five seconds and 30 milliseconds of network timeout.
|
||||
|
||||
#### `strategy`
|
||||
##### `strategy`
|
||||
|
||||
The Angular service worker can use either of two caching strategies for data resources.
|
||||
|
||||
@@ -309,19 +322,19 @@ The Angular service worker can use either of two caching strategies for data res
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
You can also emulate a third strategy, [staleWhileRevalidate](https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#stale-while-revalidate), which returns cached data \(if available\), but also fetches fresh data from the network in the background for next time.
|
||||
You can also emulate a third strategy, [staleWhileRevalidate](https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#stale-while-revalidate), which returns cached data if it is available, but also fetches fresh data from the network in the background for next time.
|
||||
To use this strategy set `strategy` to `freshness` and `timeout` to `0u` in `cacheConfig`.
|
||||
|
||||
This essentially does the following:
|
||||
|
||||
1. Try to fetch from the network first.
|
||||
1. If the network request does not complete after 0ms \(that is, immediately\), fall back to the cache \(ignoring cache age\).
|
||||
1. Once the network request completes, update the cache for future requests.
|
||||
1. If the resource does not exist in the cache, wait for the network request anyway.
|
||||
2. If the network request does not complete immediately, that is after a timeout of 0 ms, ignore the cache age and fall back to the cached value.
|
||||
3. Once the network request completes, update the cache for future requests.
|
||||
4. If the resource does not exist in the cache, wait for the network request anyway.
|
||||
|
||||
</div>
|
||||
|
||||
#### `cacheOpaqueResponses`
|
||||
##### `cacheOpaqueResponses`
|
||||
|
||||
Whether the Angular service worker should cache opaque responses or not.
|
||||
|
||||
@@ -329,8 +342,8 @@ If not specified, the default value depends on the data group's configured strat
|
||||
|
||||
| Strategies | Details |
|
||||
|:--- |:--- |
|
||||
| Groups with the `freshness` strategy | The default value is `true` \(cache opaque responses\). These groups will request the data anew every time, only falling back to the cached response when offline or on a slow network. Therefore, it doesn't matter if the service worker caches an error response. |
|
||||
| Groups with the `performance` strategy | The default value is `false` \(do not cache opaque responses\). These groups would continue to return a cached response until `maxAge` expires, even if the error was due to a temporary network or server issue. Therefore, it would be problematic for the service worker to cache an error response. |
|
||||
| Groups with the `freshness` strategy | The default value is `true` and the service worker caches opaque responses. These groups will request the data every time and only fall back to the cached response when offline or on a slow network. Therefore, it doesn't matter if the service worker caches an error response. |
|
||||
| Groups with the `performance` strategy | The default value is `false` and the service worker doesn't cache opaque responses. These groups would continue to return a cached response until `maxAge` expires, even if the error was due to a temporary network or server issue. Therefore, it would be problematic for the service worker to cache an error response. |
|
||||
|
||||
<div class="callout is-important">
|
||||
|
||||
@@ -344,27 +357,24 @@ If you are not able to implement CORS —for example, if you don't control t
|
||||
|
||||
</div>
|
||||
|
||||
### `cacheQueryOptions`
|
||||
#### `cacheQueryOptions`
|
||||
|
||||
See [assetGroups](#assetgroups) for details.
|
||||
|
||||
## `navigationUrls`
|
||||
### `navigationUrls`
|
||||
|
||||
This optional section enables you to specify a custom list of URLs that will be redirected to the index file.
|
||||
|
||||
### Handling navigation requests
|
||||
#### Handling navigation requests
|
||||
|
||||
The ServiceWorker redirects navigation requests that don't match any `asset` or `data` group to the specified [index file](#index-file).
|
||||
A request is considered to be a navigation request if:
|
||||
|
||||
* Its [mode](https://developer.mozilla.org/docs/Web/API/Request/mode) is `navigation`
|
||||
* It accepts a `text/html` response \(as determined by the value of the `Accept` header\)
|
||||
* Its URL matches certain criteria \(see the following\)
|
||||
|
||||
By default, these criteria are:
|
||||
|
||||
* The URL must not contain a file extension \(that is, a `.`\) in the last path segment
|
||||
* The URL must not contain `__`
|
||||
* It accepts a `text/html` response as determined by the value of the `Accept` header
|
||||
* Its URL matches the following criteria:
|
||||
* The URL must not contain a file extension \(that is, a `.`\) in the last path segment
|
||||
* The URL must not contain `__`
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@@ -372,10 +382,10 @@ To configure whether navigation requests are sent through to the network or not,
|
||||
|
||||
</div>
|
||||
|
||||
### Matching navigation request URLs
|
||||
#### Matching navigation request URLs
|
||||
|
||||
While these default criteria are fine in most cases, it is sometimes desirable to configure different rules.
|
||||
For example, you might want to ignore specific routes \(that are not part of the Angular app\) and pass them through to the server.
|
||||
For example, you might want to ignore specific routes, such as those that are not part of the Angular app, and pass them through to the server.
|
||||
|
||||
This field contains an array of URLs and [glob-like](#glob-patterns) URL patterns that are matched at runtime.
|
||||
It can contain both negative patterns \(that is, patterns starting with `!`\) and non-negative patterns and URLs.
|
||||
@@ -398,7 +408,7 @@ If the field is omitted, it defaults to:
|
||||
|
||||
<a id="navigation-request-strategy"></a>
|
||||
|
||||
## `navigationRequestStrategy`
|
||||
### `navigationRequestStrategy`
|
||||
|
||||
This optional property enables you to configure how the service worker handles navigation requests:
|
||||
|
||||
@@ -413,7 +423,7 @@ This optional property enables you to configure how the service worker handles n
|
||||
| Possible values | Details |
|
||||
|:--- |:--- |
|
||||
| `'performance'` | The default setting. Serves the specified [index file](#index-file), which is typically cached. |
|
||||
| `'freshness'` | Passes the requests through to the network and falls back to the `performance` behavior when offline. This value is useful when the server redirects the navigation requests elsewhere using an HTTP redirect \(3xx status code\). Reasons for using this value include: <ul> <li> Redirecting to an authentication website when authentication is not handled by the application </li> <li> Redirecting specific URLs to avoid breaking existing links/bookmarks after a website redesign </li> <li> Redirecting to a different website, such as a server-status page, while a page is temporarily down </li> </ul> |
|
||||
| `'freshness'` | Passes the requests through to the network and falls back to the `performance` behavior when offline. This value is useful when the server redirects the navigation requests elsewhere using a `3xx` HTTP redirect status code. Reasons for using this value include: <ul> <li> Redirecting to an authentication website when authentication is not handled by the application </li> <li> Redirecting specific URLs to avoid breaking existing links/bookmarks after a website redesign </li> <li> Redirecting to a different website, such as a server-status page, while a page is temporarily down </li> </ul> |
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
|
||||
@@ -9,21 +9,21 @@ A basic understanding of the following:
|
||||
|
||||
* [Service Worker Communication](guide/service-worker-communications)
|
||||
|
||||
## Service worker and caching of app resources
|
||||
## Service worker and caching of application resources
|
||||
|
||||
Conceptually, imagine the Angular service worker as a forward cache or a CDN edge that is installed in the end user's web browser.
|
||||
The service worker's job is to satisfy requests made by the Angular application for resources or data from a local cache, without needing to wait for the network.
|
||||
Imagine the Angular service worker as a forward cache or a Content Delivery Network (CDN) edge that is installed in the end user's web browser.
|
||||
The service worker responds to requests made by the Angular application for resources or data from a local cache, without needing to wait for the network.
|
||||
Like any cache, it has rules for how content is expired and updated.
|
||||
|
||||
<a id="versions"></a>
|
||||
|
||||
### App versions
|
||||
### Application versions
|
||||
|
||||
In the context of an Angular service worker, a "version" is a collection of resources that represent a specific build of the Angular application.
|
||||
Whenever a new build of the application is deployed, the service worker treats that build as a new version of the application.
|
||||
This is true even if only a single file is updated.
|
||||
At any given time, the service worker might have multiple versions of the application in its cache and it might be serving them simultaneously.
|
||||
For more information, see the [App tabs](guide/service-worker-devops#tabs) section below.
|
||||
For more information, see the [Application tabs](guide/service-worker-devops#tabs) section.
|
||||
|
||||
To preserve application integrity, the Angular service worker groups all files into a version together.
|
||||
The files grouped into a version usually include HTML, JS, and CSS files.
|
||||
@@ -35,15 +35,15 @@ In this scenario, it is not valid to serve the old `index.html`, which calls `st
|
||||
|
||||
This file integrity is especially important when lazy loading modules.
|
||||
A JS bundle might reference many lazy chunks, and the filenames of the lazy chunks are unique to the particular build of the application.
|
||||
If a running application at version `X` attempts to load a lazy chunk, but the server has already updated to version `X + 1`, the lazy loading operation will fail.
|
||||
If a running application at version `X` attempts to load a lazy chunk, but the server has already updated to version `X + 1`, the lazy loading operation fails.
|
||||
|
||||
The version identifier of the application is determined by the contents of all resources, and it changes if any of them change.
|
||||
In practice, the version is determined by the contents of the `ngsw.json` file, which includes hashes for all known content.
|
||||
If any of the cached files change, the file's hash will change in `ngsw.json`, causing the Angular service worker to treat the active set of files as a new version.
|
||||
If any of the cached files change, the file's hash changes in `ngsw.json`. This change causes the Angular service worker to treat the active set of files as a new version.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
`ngsw.json` is the manifest file that is generated at build time based on `ngsw-config.json`.
|
||||
The build process creates the manifest file, `ngsw.json`, using information from `ngsw-config.json`.
|
||||
|
||||
</div>
|
||||
|
||||
@@ -52,25 +52,27 @@ With the versioning behavior of the Angular service worker, an application serve
|
||||
#### Update checks
|
||||
|
||||
Every time the user opens or refreshes the application, the Angular service worker checks for updates to the application by looking for updates to the `ngsw.json` manifest.
|
||||
If an update is found, it is downloaded and cached automatically, and will be served the next time the application is loaded.
|
||||
If an update is found, it is downloaded and cached automatically, and is served the next time the application is loaded.
|
||||
|
||||
### Resource integrity
|
||||
|
||||
One of the potential side effects of long caching is inadvertently caching an invalid resource.
|
||||
In a normal HTTP cache, a hard refresh or cache expiration limits the negative effects of caching an invalid file.
|
||||
A service worker ignores such constraints and effectively long caches the entire application.
|
||||
Consequently, it is essential that the service worker gets the correct content.
|
||||
One of the potential side effects of long caching is inadvertently caching a resource that's not valid.
|
||||
In a normal HTTP cache, a hard refresh or the cache expiring limits the negative effects of caching a file that's not valid.
|
||||
A service worker ignores such constraints and effectively long-caches the entire application.
|
||||
It's important that the service worker gets the correct content, so it keeps hashes of the resources to maintain their integrity.
|
||||
|
||||
#### Hashed content
|
||||
|
||||
To ensure resource integrity, the Angular service worker validates the hashes of all resources for which it has a hash.
|
||||
Typically for an application created with the [Angular CLI](cli), this is everything in the `dist` directory covered by the user's `src/ngsw-config.json` configuration.
|
||||
For an application created with the [Angular CLI](cli), this is everything in the `dist` directory covered by the user's `src/ngsw-config.json` configuration.
|
||||
|
||||
If a particular file fails validation, the Angular service worker attempts to re-fetch the content using a "cache-busting" URL parameter to eliminate the effects of browser or intermediate caching.
|
||||
If that content also fails validation, the service worker considers the entire version of the application to be invalid and it stops serving the application.
|
||||
If necessary, the service worker enters a safe mode where requests fall back on the network, opting not to use its cache if the risk of serving invalid, broken, or outdated content is high.
|
||||
If a particular file fails validation, the Angular service worker attempts to re-fetch the content using a "cache-busting" URL parameter to prevent browser or intermediate caching.
|
||||
If that content also fails validation, the service worker considers the entire version of the application to not be valid and stops serving the application.
|
||||
If necessary, the service worker enters a safe mode where requests fall back on the network. The service worker doesn't use its cache if there's a high risk of serving content that is broken, outdated, or not valid.
|
||||
|
||||
Hash mismatches can occur for a variety of reasons:
|
||||
|
||||
* Caching layers in between the origin server and the end user could serve stale content
|
||||
* Caching layers between the origin server and the end user could serve stale content
|
||||
* A non-atomic deployment could result in the Angular service worker having visibility of partially updated content
|
||||
* Errors during the build process could result in updated resources without `ngsw.json` being updated.
|
||||
The reverse could also happen resulting in an updated `ngsw.json` without updated resources.
|
||||
@@ -80,36 +82,36 @@ Hash mismatches can occur for a variety of reasons:
|
||||
The only resources that have hashes in the `ngsw.json` manifest are resources that were present in the `dist` directory at the time the manifest was built.
|
||||
Other resources, especially those loaded from CDNs, have content that is unknown at build time or are updated more frequently than the application is deployed.
|
||||
|
||||
If the Angular service worker does not have a hash to validate a given resource, it still caches its contents but it honors the HTTP caching headers by using a policy of "stale while revalidate".
|
||||
That is, when HTTP caching headers for a cached resource indicate that the resource has expired, the Angular service worker continues to serve the content and it attempts to refresh the resource in the background.
|
||||
If the Angular service worker does not have a hash to verify a resource is valid, it still caches its contents. At the same time, it honors the HTTP caching headers by using a policy of *stale while revalidate*.
|
||||
The Angular service worker continues to serve a resource even after its HTTP caching headers indicate
|
||||
that it is no longer valid. At the same time, it attempts to refresh the expired resource in the background.
|
||||
This way, broken unhashed resources do not remain in the cache beyond their configured lifetimes.
|
||||
|
||||
<a id="tabs"></a>
|
||||
|
||||
### App tabs
|
||||
### Application tabs
|
||||
|
||||
It can be problematic for an application if the version of resources it's receiving changes suddenly or without warning.
|
||||
See the [App versions](guide/service-worker-devops#versions) section above for a description of such issues.
|
||||
See the [Application versions](guide/service-worker-devops#versions) section for a description of such issues.
|
||||
|
||||
The Angular service worker provides a guarantee: a running application will continue to run the same version of the application.
|
||||
If another instance of the application is opened in a new web browser tab, then the most current version of the app is served.
|
||||
The Angular service worker provides a guarantee: a running application continues to run the same version of the application.
|
||||
If another instance of the application is opened in a new web browser tab, then the most current version of the application is served.
|
||||
As a result, that new tab can be running a different version of the application than the original tab.
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
**IMPORTANT**: <br />
|
||||
This guarantee is **stronger** than that provided by the normal web deployment model.
|
||||
Without a service worker, there is no guarantee that code lazily loaded later in a running application is from the same version as the initial code for the application.
|
||||
Without a service worker, there is no guarantee that lazily loaded code is from the same version as the application's initial code.
|
||||
|
||||
</div>
|
||||
|
||||
There are a few limited reasons why the Angular service worker might change the version of a running application.
|
||||
Some of them are error conditions:
|
||||
The Angular service worker might change the version of a running application under error conditions such as:
|
||||
|
||||
* The current version becomes invalid due to a failed hash
|
||||
* An unrelated error causes the service worker to enter safe mode; that is, temporary deactivation
|
||||
* The current version becomes non-valid due to a failed hash
|
||||
* An unrelated error causes the service worker to enter safe mode and deactivates it temporarily
|
||||
|
||||
The Angular service worker is aware of which versions are in use at any given moment and it cleans up versions when no tab is using them.
|
||||
The Angular service worker cleans up application versions when no tab is using them.
|
||||
|
||||
Other reasons the Angular service worker might change the version of a running application are normal events:
|
||||
|
||||
@@ -119,27 +121,35 @@ Other reasons the Angular service worker might change the version of a running a
|
||||
### Service worker updates
|
||||
|
||||
The Angular service worker is a small script that runs in web browsers.
|
||||
From time to time, the service worker will be updated with bug fixes and feature improvements.
|
||||
From time to time, the service worker is updated with bug fixes and feature improvements.
|
||||
|
||||
The Angular service worker is downloaded when the application is first opened and when the application is accessed after a period of inactivity.
|
||||
If the service worker has changed, the service worker will be updated in the background.
|
||||
If the service worker changes, it's updated in the background.
|
||||
|
||||
Most updates to the Angular service worker are transparent to the app —the old caches are still valid and content is still served
|
||||
normally.
|
||||
However, occasionally a bugfix or feature in the Angular service worker requires the invalidation of old caches.
|
||||
In this case, the application will be refreshed transparently from the network.
|
||||
Most updates to the Angular service worker are transparent to the application. The old caches are still valid and content is still served normally.
|
||||
Occasionally, a bug fix or feature in the Angular service worker might require the invalidation of old caches.
|
||||
In this case, the service worker transparently refreshes the application from the network.
|
||||
|
||||
### Bypassing the service worker
|
||||
|
||||
In some cases, you might want to bypass the service worker entirely and let the browser handle the request instead.
|
||||
An example is when you rely on a feature that is currently not supported in service workers \(for example, [reporting progress on uploaded files](https://github.com/w3c/ServiceWorker/issues/1141)\).
|
||||
In some cases, you might want to bypass the service worker entirely and let the browser handle the request.
|
||||
An example is when you rely on a feature that is currently not supported in service workers, such as [reporting progress on uploaded files](https://github.com/w3c/ServiceWorker/issues/1141).
|
||||
|
||||
To bypass the service worker, set `ngsw-bypass` as a request header, or as a query parameter.
|
||||
\(The value of the header or query parameter is ignored and can be empty or omitted.\)
|
||||
The value of the header or query parameter is ignored and can be empty or omitted.
|
||||
|
||||
### Service worker requests when the server can't be reached
|
||||
|
||||
The service worker processes all requests unless the [service worker is explicitly bypassed](#bypassing-the-service-worker).
|
||||
The service worker either returns a cached response or sends the request to the server, depending on the state and configuration of the cache.
|
||||
The service worker only caches responses to non-mutating requests, such as `GET` and `HEAD`.
|
||||
|
||||
If the service worker receives an error from the server or it doesn't receive a response, it returns an error status that indicates the result of the call.
|
||||
For example, if the service worker doesn't receive a response, it creates a [504 Gateway Timeout](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504) status to return. The `504` status in this example could be returned because the server is offline or the client is disconnected.
|
||||
|
||||
## Debugging the Angular service worker
|
||||
|
||||
Occasionally, it might be necessary to examine the Angular service worker in a running state to investigate issues or to ensure that it is operating as designed.
|
||||
Occasionally, it might be necessary to examine the Angular service worker in a running state to investigate issues or whether it's operating as designed.
|
||||
Browsers provide built-in tools for debugging service workers and the Angular service worker itself includes useful debugging features.
|
||||
|
||||
### Locating and analyzing debugging information
|
||||
@@ -187,7 +197,7 @@ There are two possible degraded states:
|
||||
|
||||
| Degraded states | Details |
|
||||
|:--- |:--- |
|
||||
| `EXISTING_CLIENTS_ONLY` | The service worker does not have a clean copy of the latest known version of the application. Older cached versions are safe to use, so existing tabs continue to run from cache, but new loads of the application will be served from the network. The service worker will try to recover from this state when a new version of the application is detected and installed \(that is, when a new `ngsw.json` is available\). |
|
||||
| `EXISTING_CLIENTS_ONLY` | The service worker does not have a clean copy of the latest known version of the application. Older cached versions are safe to use, so existing tabs continue to run from cache, but new loads of the application will be served from the network. The service worker will try to recover from this state when a new version of the application is detected and installed. This happens when a new `ngsw.json` is available. |
|
||||
| `SAFE_MODE` | The service worker cannot guarantee the safety of using cached data. Either an unexpected error occurred or all cached versions are invalid. All traffic will be served from the network, running as little service worker code as possible. |
|
||||
|
||||
In both cases, the parenthetical annotation provides the
|
||||
@@ -269,9 +279,9 @@ Debug log:
|
||||
|
||||
</code-example>
|
||||
|
||||
Errors that occur within the service worker will be logged here.
|
||||
Errors that occur within the service worker are logged here.
|
||||
|
||||
### Developer Tools
|
||||
### Developer tools
|
||||
|
||||
Browsers such as Chrome provide developer tools for interacting with service workers.
|
||||
Such tools can be powerful when used properly, but there are a few things to keep in mind.
|
||||
@@ -282,23 +292,28 @@ Such tools can be powerful when used properly, but there are a few things to kee
|
||||
* If you look in the Cache Storage viewer, the cache is frequently out of date.
|
||||
Right click the Cache Storage title and refresh the caches.
|
||||
|
||||
* Stopping and starting the service worker in the Service Worker pane triggers a check for updates
|
||||
* Stopping and starting the service worker in the Service Worker pane checks for updates
|
||||
|
||||
## Service Worker Safety
|
||||
## Service worker safety
|
||||
|
||||
Like any complex system, bugs or broken configurations can cause the Angular service worker to act in unforeseen ways.
|
||||
While its design attempts to minimize the impact of such problems, the Angular service worker contains several failsafe mechanisms in case an administrator ever needs to deactivate the service worker quickly.
|
||||
Bugs or broken configurations could cause the Angular service worker to act in unexpected ways.
|
||||
If this happens, the Angular service worker contains several failsafe mechanisms in case an administrator needs to deactivate the service worker quickly.
|
||||
|
||||
### Fail-safe
|
||||
|
||||
To deactivate the service worker, remove or rename the `ngsw.json` file.
|
||||
When the service worker's request for `ngsw.json` returns a `404`, then the service worker removes all of its caches and de-registers itself, essentially self-destructing.
|
||||
To deactivate the service worker, rename the `ngsw.json` file or delete it.
|
||||
When the service worker's request for `ngsw.json` returns a `404`, then the service worker removes all its caches and de-registers itself, essentially self-destructing.
|
||||
|
||||
### Safety Worker
|
||||
### Safety worker
|
||||
|
||||
Also included in the `@angular/service-worker` NPM package is a small script `safety-worker.js`, which when loaded will unregister itself from the browser and remove the service worker caches.
|
||||
<!-- vale Angular.Google_Acronyms = NO -->
|
||||
|
||||
A small script, `safety-worker.js`, is also included in the `@angular/service-worker` NPM package.
|
||||
When loaded, it un-registers itself from the browser and removes the service worker caches.
|
||||
This script can be used as a last resort to get rid of unwanted service workers already installed on client pages.
|
||||
|
||||
<!-- vale Angular.Google_Acronyms = YES -->
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
**IMPORTANT**: <br />
|
||||
@@ -306,11 +321,11 @@ You cannot register this worker directly, as old clients with cached state might
|
||||
|
||||
</div>
|
||||
|
||||
Instead, you must serve the contents of `safety-worker.js` at the URL of the Service Worker script you are trying to unregister, and must continue to do so until you are certain all users have successfully unregistered the old worker.
|
||||
Instead, you must serve the contents of `safety-worker.js` at the URL of the Service Worker script you are trying to unregister. You must continue to do so until you are certain all users have successfully unregistered the old worker.
|
||||
For most sites, this means that you should serve the safety worker at the old Service Worker URL forever.
|
||||
This script can be used both to deactivate `@angular/service-worker` \(and remove the corresponding caches\) as well as any other Service Workers which might have been served in the past on your site.
|
||||
This script can be used to deactivate `@angular/service-worker` and remove the corresponding caches. It also removes any other Service Workers which might have been served in the past on your site.
|
||||
|
||||
### Changing your app's location
|
||||
### Changing your application's location
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
@@ -321,11 +336,11 @@ You might have already encountered the error `The script resource is behind a re
|
||||
</div>
|
||||
|
||||
This can be a problem if you have to change your application's location.
|
||||
If you setup a redirect from the old location \(for example `example.com`\) to the new location \(for example `www.example.com`\) the worker will stop working.
|
||||
If you setup a redirect from the old location, such as `example.com`, to the new location, `www.example.com` in this example, the worker stops working.
|
||||
Also, the redirect won't even trigger for users who are loading the site entirely from Service Worker.
|
||||
The old worker \(registered at `example.com`\) tries to update and sends requests to the old location `example.com` which get redirected to the new location `www.example.com` and create the error `The script resource is behind a redirect, which is disallowed`.
|
||||
The old worker, which was registered at `example.com`, tries to update and sends a request to the old location `example.com`. This request is redirected to the new location `www.example.com` and creates the error: `The script resource is behind a redirect, which is disallowed`.
|
||||
|
||||
To remedy this, you might need to deactivate the old worker using one of the above techniques \([Fail-safe](#fail-safe) or [Safety Worker](#safety-worker)\).
|
||||
To remedy this, you might need to deactivate the old worker using one of the preceding techniques: [Fail-safe](#fail-safe) or [Safety Worker](#safety-worker).
|
||||
|
||||
## More on Angular service workers
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This guide is about structural directives and provides conceptual information on how such directives work, how Angular interprets their shorthand syntax, and how to add template guard properties to catch template type errors.
|
||||
|
||||
Structural directives are directives which change the DOM layout by adding and removing DOM element.
|
||||
Structural directives are directives which change the DOM layout by adding and removing DOM elements.
|
||||
|
||||
Angular provides a set of built-in structural directives (such as `NgIf`, `NgForOf`, `NgSwitch` and others) which are commonly used in all Angular projects. For more information see [Built-in directives](guide/built-in-directives).
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ Debug specs in the browser in the same way that you debug an application.
|
||||
1. Reveal the Karma browser window.
|
||||
See [Set up testing](guide/testing#set-up-testing) if you need help with this step.
|
||||
|
||||
1. Click the **DEBUG** button; it opens a new browser tab and re-runs the tests.
|
||||
1. Open the browser's "Developer Tools" \(`Ctrl-Shift-I` on Windows; `Command-Option-I` in macOS\).
|
||||
1. Pick the "sources" section.
|
||||
1. Open the `1st.spec.ts` test file \(Control/Command-P, then start typing the name of the file\).
|
||||
1. Set a breakpoint in the test.
|
||||
1. Refresh the browser, and it stops at the breakpoint.
|
||||
1. Click the **DEBUG** button to open a new browser tab and re-run the tests.
|
||||
2. Open the browser's **Developer Tools**. On Windows, press `Ctrl-Shift-I`. On macOS, press `Command-Option-I`.
|
||||
3. Pick the **Sources** section.
|
||||
4. Press `Control/Command-P`, and then start typing the name of your test file to open it.
|
||||
5. Set a breakpoint in the test.
|
||||
6. Refresh the browser, and notice how it stops at the breakpoint.
|
||||
|
||||
<div class="lightbox">
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ To adequately test a component, you should test that they work together as inten
|
||||
Such tests require creating the component's host element in the browser DOM, as Angular does, and investigating the component class's interaction with the DOM as described by its template.
|
||||
|
||||
The Angular `TestBed` facilitates this kind of testing as you'll see in the following sections.
|
||||
But in many cases, *testing the component class alone*, without DOM involvement, can validate much of the component's behavior in an straightforward, more obvious way.
|
||||
But in many cases, *testing the component class alone*, without DOM involvement, can validate much of the component's behavior in a straightforward, more obvious way.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ email.reset();
|
||||
console.log(email.value); // null
|
||||
```
|
||||
|
||||
TypeScript will enforce that you always handle the possibility that the control has become `null`. If you want to make this control non-nullable, you may use the `nonNullable` option. This will cause the control to reset to its intial value, instead of `null`:
|
||||
TypeScript will enforce that you always handle the possibility that the control has become `null`. If you want to make this control non-nullable, you may use the `nonNullable` option. This will cause the control to reset to its initial value, instead of `null`:
|
||||
|
||||
```ts
|
||||
const email = new FormControl('angularrox@gmail.com', {nonNullable: true});
|
||||
|
||||
@@ -1687,7 +1687,6 @@ And for the phone list component, a few adjustments to the router make the `Rout
|
||||
[AioGuideAotCompiler]: guide/aot-compiler "Ahead-of-time (AOT) compilation | Angular"
|
||||
[AioGuideBuiltInDirectives]: guide/built-in-directives "Built-in directives | Angular"
|
||||
[AioGuideDependencyInjection]: guide/dependency-injection "Dependency injection in Angular | Angular"
|
||||
[AioGuideDependencyInjectionProvidersFactoryProviders]: guide/dependency-injection-providers#factory-providers "Using factory providers - Dependency providers | Angular"
|
||||
[AioGuideGlossaryLazyLoading]: guide/glossary#lazy-loading "lazy loading - Glossary | Angular"
|
||||
[AioGuideHierarchicalDependencyInjection]: guide/hierarchical-dependency-injection "Hierarchical injectors | Angular"
|
||||
[AioGuideLifecycleHooks]: guide/lifecycle-hooks "Lifecycle hooks | Angular"
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 622 B |
Binary file not shown.
|
After Width: | Height: | Size: 508 B |
Binary file not shown.
|
After Width: | Height: | Size: 447 B |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -101,6 +101,14 @@
|
||||
"bio": "SDE III @cisco | GDE for Angular | Microsoft MVP | Author | Speaker | Passionate Programmer",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
"antoniocardenas": {
|
||||
"name": "Antonio Cardenas",
|
||||
"picture": "antonio-cardenas.jpg",
|
||||
"twitter": "yeoudev",
|
||||
"website": "https://yeou.dev",
|
||||
"bio": "Antonio is a senior Angular developer from Honduras, focus on immersive experiences and Web Performance, He is a public Speaker, Mentor and Facilitator for entrepreneurship programs as Techstars Startup Weekend, Content Creator and tech writer Cofounder of non profit organization @Macaotech, Love to share knowledge Typescript Coffe and Cats 🐱.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
"armenvardanyan95": {
|
||||
"name": "Armen Vardanyan",
|
||||
"picture": "armen-vardanyan.jpg",
|
||||
@@ -845,6 +853,15 @@
|
||||
"twitter": "SiddAjmera",
|
||||
"bio": "Siddharth is a Full Stack JavaScript Developer and a GDE in Angular. He's passionate about sharing his knowledge on Angular, Firebase and the Web in general. He's the organizer of WebStack, a local community of developers focused on Web, Mobile, Voice and Server related technologies in general. WebStack hosts free monthly meetups every 2nd or 3rd Saturday of the month. Siddharth is also an avid photographer and loves traveling. Find him anywhere on the Web with `SiddAjmera`.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
"simonaco": {
|
||||
"name": "Simona Cotin",
|
||||
"picture": "simonacotin.jpg",
|
||||
"twitter": "simona_cotin",
|
||||
"website": "https://github.com/simonaco",
|
||||
"bio": "Engineering manager working on Angular Framework and Tooling",
|
||||
"groups": ["Angular"],
|
||||
"lead": "madleinas"
|
||||
},
|
||||
"simpulton": {
|
||||
"name": "Lukas Ruebbelke",
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
"desc": "NativeScript is how you build cross-platform, native iOS and Android apps with Angular and TypeScript. Get 100% access to native APIs via JavaScript and reuse of packages from NPM, CocoaPods and Gradle. Open source and backed by Telerik.",
|
||||
"logo": "",
|
||||
"title": "NativeScript",
|
||||
"url": "https://docs.nativescript.org/angular/start/introduction"
|
||||
"url": "https://docs.nativescript.org/tutorial/angular.html"
|
||||
},
|
||||
"angular-miniprogram": {
|
||||
"desc": "MiniProgram Platform for Angular.",
|
||||
|
||||
+24
-14
@@ -276,15 +276,30 @@
|
||||
"title": "Dependency Injection",
|
||||
"tooltip": "Dependency Injection: creating and injecting services",
|
||||
"children": [
|
||||
{
|
||||
"url": "guide/dependency-injection-overview",
|
||||
"title": "Dependency injection in Angular",
|
||||
"tooltip": "Dependency injection is a design pattern in which a class requests dependencies from external sources."
|
||||
},
|
||||
{
|
||||
"url": "guide/dependency-injection",
|
||||
"title": "Angular Dependency Injection",
|
||||
"title": "Understanding Dependency Injection",
|
||||
"tooltip": "Angular's dependency injection system creates and delivers dependent services to Angular-created classes."
|
||||
},
|
||||
{
|
||||
"url": "guide/creating-injectable-service",
|
||||
"title": "Creating an injectable service",
|
||||
"tooltip": "Example of creating an injectable service."
|
||||
},
|
||||
{
|
||||
"url": "guide/dependency-injection-providers",
|
||||
"title": "DI Providers",
|
||||
"tooltip": "More about the different kinds of providers."
|
||||
"title": "Defining Dependency providers",
|
||||
"tooltip": "A provider factory function is a plain function that Angular can call to create a dependency."
|
||||
},
|
||||
{
|
||||
"url": "guide/hierarchical-dependency-injection",
|
||||
"title": "Hierarchical injectors",
|
||||
"tooltip": "Hierarchical dependency injection enables you to share dependencies between different parts of the application only when and if you need to."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -923,11 +938,6 @@
|
||||
"title": "Intro to Components",
|
||||
"tooltip": "About Components, Templates, and Views."
|
||||
},
|
||||
{
|
||||
"url": "guide/architecture-services",
|
||||
"title": "Intro to Services and DI",
|
||||
"tooltip": "About services and dependency injection."
|
||||
},
|
||||
{
|
||||
"url": "guide/architecture-next-steps",
|
||||
"title": "Next Steps",
|
||||
@@ -1083,11 +1093,6 @@
|
||||
"title": "Dependency injection",
|
||||
"tooltip": "Using dependency injection in Angular.",
|
||||
"children": [
|
||||
{
|
||||
"url": "guide/hierarchical-dependency-injection",
|
||||
"title": "Hierarchical Injectors",
|
||||
"tooltip": "An injector tree parallels the component tree and supports nested dependencies."
|
||||
},
|
||||
{
|
||||
"url": "guide/dependency-injection-in-action",
|
||||
"title": "DI in Action",
|
||||
@@ -1167,7 +1172,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Content Contributor's Guide",
|
||||
"title": "Documentation Contributor's Guide",
|
||||
"tooltip": "Describes how to contribute to the Angular documentation.",
|
||||
"children": [
|
||||
{
|
||||
@@ -1195,6 +1200,11 @@
|
||||
"title": "Documentation Style Guide",
|
||||
"tooltip": "Style guide for documentation authors."
|
||||
},
|
||||
{
|
||||
"url": "guide/docs-lint-errors",
|
||||
"title": "Resolving documentation linter messages",
|
||||
"tooltip": "More information about documentation lint errors."
|
||||
},
|
||||
{
|
||||
"url": "guide/localizing-angular",
|
||||
"title": "Angular doc localization guidelines",
|
||||
|
||||
@@ -74,7 +74,7 @@ After the browser refreshes, the list of heroes appears.
|
||||
|
||||
<header>Interactive elements</header>
|
||||
|
||||
Inside the `<li>` element, add a `<button>` element to wrap the hero's details, and then make the hero clickable. To improve accessibility, use HTML elements that are inherently interactive instead of adding an event listeners to a non-interactive elements. In this case, the interactive `<button>` element is instead of adding an event to the `<li>` element.
|
||||
Inside the `<li>` element, add a `<button>` element to wrap the hero's details, and then make the hero clickable. To improve accessibility, use HTML elements that are inherently interactive instead of adding an event listener to a non-interactive element. In this case, the interactive `<button>` element is used instead of adding an event to the `<li>` element.
|
||||
|
||||
For more details on accessibility, see [Accessibility in Angular](guide/accessibility).
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
{"type": 301, "source": "/getting-started", "destination": "/start"},
|
||||
{"type": 301, "source": "/getting-started/:rest*", "destination": "/start/:rest*"},
|
||||
{"type": 301, "source": "/guide/displaying-data", "destination": "/start#template-syntax"},
|
||||
{"type": 301, "source": "/guide/ivy", "destination": "https://v12.angular.io/guide/ivy"},
|
||||
{"type": 301, "source": "/guide/updating-to-version-10", "destination": "https://v10.angular.io/guide/updating-to-version-10"},
|
||||
{"type": 301, "source": "/guide/updating-to-version-11", "destination": "https://v11.angular.io/guide/updating-to-version-11"},
|
||||
{"type": 301, "source": "/guide/updating-to-version-12", "destination": "/guide/update-to-latest-version"},
|
||||
|
||||
@@ -118,6 +118,7 @@
|
||||
"!/guide/cli-quickstart/{0,1}",
|
||||
"!/guide/displaying-data/{0,1}",
|
||||
"!/guide/i18n/{0,1}",
|
||||
"!/guide/ivy/{0,1}",
|
||||
"!/guide/learning-angular*",
|
||||
"!/guide/metadata/{0,1}",
|
||||
"!/guide/ngmodule/{0,1}",
|
||||
|
||||
+8
-8
@@ -100,12 +100,12 @@
|
||||
"@angular/router": "^14.1.0-next",
|
||||
"@angular/service-worker": "^14.1.0-next",
|
||||
"rxjs": "~7.5.0",
|
||||
"safevalues": "^0.1.8",
|
||||
"safevalues": "^0.3.1",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/architect-cli": "0.1401.0-next.4",
|
||||
"@angular-devkit/architect-cli": "0.1401.0-rc.3",
|
||||
"@angular-devkit/build-angular": "^14.1.0-next",
|
||||
"@angular-eslint/builder": "^14.0.0",
|
||||
"@angular-eslint/eslint-plugin": "^14.0.0",
|
||||
@@ -119,8 +119,8 @@
|
||||
"@types/node": "^12.7.9",
|
||||
"@types/trusted-types": "^2.0.2",
|
||||
"@types/xregexp": "^4.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.30.6",
|
||||
"@typescript-eslint/parser": "5.30.6",
|
||||
"@typescript-eslint/eslint-plugin": "5.33.0",
|
||||
"@typescript-eslint/parser": "5.33.0",
|
||||
"@yarnpkg/lockfile": "^1.1.0",
|
||||
"archiver": "^5.3.0",
|
||||
"assert": "^2.0.0",
|
||||
@@ -147,16 +147,16 @@
|
||||
"html": "^1.0.0",
|
||||
"ignore": "^5.1.8",
|
||||
"image-size": "^1.0.0",
|
||||
"jasmine": "~4.2.0",
|
||||
"jasmine-core": "~4.2.0",
|
||||
"jasmine": "~4.3.0",
|
||||
"jasmine-core": "~4.3.0",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"jsdom": "^20.0.0",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"json5": "^2.2.0",
|
||||
"karma": "~6.3.2",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.0.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.0.0",
|
||||
"light-server": "^2.9.1",
|
||||
"lighthouse": "^9.0.0",
|
||||
|
||||
@@ -13,7 +13,7 @@ import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
|
||||
import { svg } from 'app/shared/security';
|
||||
import { scriptUrl, unwrapScriptUrlForSink } from 'safevalues';
|
||||
import { trustedResourceUrl, unwrapResourceUrl } from 'safevalues';
|
||||
|
||||
import { AppComponent } from 'app/app.component';
|
||||
import { CustomIconRegistry, SVG_ICONS } from 'app/shared/custom-icon-registry';
|
||||
@@ -156,7 +156,7 @@ export const svgIconProviders = [
|
||||
SharedModule,
|
||||
ServiceWorkerModule.register(
|
||||
// Make sure service worker is loaded with a TrustedScriptURL
|
||||
unwrapScriptUrlForSink(scriptUrl`/ngsw-worker.js`),
|
||||
unwrapResourceUrl(trustedResourceUrl`/ngsw-worker.js`) as string,
|
||||
{enabled: environment.production}),
|
||||
],
|
||||
declarations: [
|
||||
|
||||
@@ -5,8 +5,8 @@ import { PrettyPrinter } from './pretty-printer.service';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { unwrapHtmlForSink } from 'safevalues';
|
||||
import { htmlFromStringKnownToSatisfyTypeContract } from 'safevalues/unsafe/reviewed';
|
||||
import { unwrapHtml } from 'safevalues';
|
||||
import { htmlSafeByReview } from 'safevalues/restricted/reviewed';
|
||||
import { fromOuterHTML } from 'app/shared/security';
|
||||
|
||||
/**
|
||||
@@ -149,7 +149,7 @@ export class CodeComponent implements OnChanges {
|
||||
private setCodeHtml(formattedCode: TrustedHTML) {
|
||||
// **Security:** Code example content is provided by docs authors and as such its considered to
|
||||
// be safe for innerHTML purposes.
|
||||
this.codeContainer.nativeElement.innerHTML = unwrapHtmlForSink(formattedCode);
|
||||
this.codeContainer.nativeElement.innerHTML = unwrapHtml(formattedCode);
|
||||
}
|
||||
|
||||
/** Gets the textContent of the displayed code element. */
|
||||
@@ -198,7 +198,7 @@ function leftAlign(text: TrustedHTML): TrustedHTML {
|
||||
}
|
||||
});
|
||||
|
||||
return htmlFromStringKnownToSatisfyTypeContract(
|
||||
return htmlSafeByReview(
|
||||
lines.map(line => line.slice(indent)).join('\n').trim(),
|
||||
'safe manipulation of existing trusted HTML');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { htmlFromStringKnownToSatisfyTypeContract } from 'safevalues/unsafe/reviewed';
|
||||
import { htmlSafeByReview } from 'safevalues/restricted/reviewed';
|
||||
|
||||
import { from, Observable } from 'rxjs';
|
||||
import { first, map, share } from 'rxjs/operators';
|
||||
@@ -51,7 +51,7 @@ export class PrettyPrinter {
|
||||
return this.prettyPrintOne.pipe(
|
||||
map(ppo => {
|
||||
try {
|
||||
return htmlFromStringKnownToSatisfyTypeContract(
|
||||
return htmlSafeByReview(
|
||||
ppo(code, language, linenums), 'prettify.js modifies already trusted HTML inline');
|
||||
} catch (err) {
|
||||
const msg = `Could not format code that begins '${code.toString().slice(0, 50)}...'.`;
|
||||
|
||||
@@ -4,7 +4,7 @@ import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||
import { AsyncSubject, Observable, of } from 'rxjs';
|
||||
import { catchError, map, switchMap, tap } from 'rxjs/operators';
|
||||
import { htmlEscape } from 'safevalues';
|
||||
import { htmlFromStringKnownToSatisfyTypeContract } from 'safevalues/unsafe/reviewed';
|
||||
import { htmlSafeByReview } from 'safevalues/restricted/reviewed';
|
||||
|
||||
import { DocumentContents, UnsafeDocumentContents } from './document-contents';
|
||||
export { DocumentContents } from './document-contents';
|
||||
@@ -17,7 +17,7 @@ export const FETCHING_ERROR_ID = 'fetching-error';
|
||||
|
||||
export const CONTENT_URL_PREFIX = 'generated/';
|
||||
export const DOC_CONTENT_URL_PREFIX = CONTENT_URL_PREFIX + 'docs/';
|
||||
const FETCHING_ERROR_CONTENTS = (path: string) => htmlFromStringKnownToSatisfyTypeContract(`
|
||||
const FETCHING_ERROR_CONTENTS = (path: string) => htmlSafeByReview(`
|
||||
<div class="nf-container l-flex-wrap flex-center">
|
||||
<div class="nf-icon material-icons">error_outline</div>
|
||||
<div class="nf-response l-flex-wrap center">
|
||||
@@ -74,7 +74,7 @@ export class DocumentService {
|
||||
null :
|
||||
// SECURITY: HTML is authored by the documentation team and is fetched directly
|
||||
// from the server
|
||||
htmlFromStringKnownToSatisfyTypeContract(data.contents, '^')
|
||||
htmlSafeByReview(data.contents, '^')
|
||||
})),
|
||||
catchError((error: HttpErrorResponse) =>
|
||||
error.status === 404 ? this.getFileNotFoundDoc(id) : this.getErrorDoc(id, error)
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Meta, Title } from '@angular/platform-browser';
|
||||
|
||||
import { Observable, asapScheduler, of, lastValueFrom } from 'rxjs';
|
||||
import { EMPTY_HTML, htmlEscape } from 'safevalues';
|
||||
import { htmlFromStringKnownToSatisfyTypeContract } from 'safevalues/unsafe/reviewed';
|
||||
import { htmlSafeByReview } from 'safevalues/restricted/reviewed';
|
||||
|
||||
import { FILE_NOT_FOUND_ID, FETCHING_ERROR_ID } from 'app/documents/document.service';
|
||||
import { CustomElementsModule } from 'app/custom-elements/custom-elements.module';
|
||||
@@ -319,7 +319,7 @@ describe('DocViewerComponent', () => {
|
||||
beforeEach(() => swapViewsSpy.and.callThrough());
|
||||
|
||||
it('should display the document contents', async () => {
|
||||
const contents = htmlFromStringKnownToSatisfyTypeContract('<h1>Hello,</h1> <div>world!</div>', 'constant HTML');
|
||||
const contents = htmlSafeByReview('<h1>Hello,</h1> <div>world!</div>', 'constant HTML');
|
||||
await doRender(contents);
|
||||
|
||||
expect(docViewerEl.innerHTML).toContain(contents.toString());
|
||||
|
||||
@@ -7,7 +7,7 @@ import {fromInnerHTML} from 'app/shared/security';
|
||||
import {TocService} from 'app/shared/toc.service';
|
||||
import {asapScheduler, Observable, of, timer} from 'rxjs';
|
||||
import {catchError, observeOn, switchMap, takeUntil, tap} from 'rxjs/operators';
|
||||
import {EMPTY_HTML, unwrapHtmlForSink} from 'safevalues';
|
||||
import {EMPTY_HTML, unwrapHtml} from 'safevalues';
|
||||
|
||||
|
||||
// Constants
|
||||
@@ -65,9 +65,9 @@ export class DocViewerComponent implements OnDestroy {
|
||||
private elementsLoader: ElementsLoader) {
|
||||
this.hostElement = elementRef.nativeElement;
|
||||
|
||||
// Security: the initialDocViewerContent comes from the prerendered DOM and is considered to be
|
||||
// secure
|
||||
this.hostElement.innerHTML = unwrapHtmlForSink(initialDocViewerContent);
|
||||
// Security: the initialDocViewerContent comes from the prerendered DOM and is
|
||||
// considered to be secure
|
||||
this.hostElement.innerHTML = unwrapHtml(initialDocViewerContent) as string;
|
||||
|
||||
if (this.hostElement.firstElementChild) {
|
||||
this.currViewContainer = this.hostElement.firstElementChild as HTMLElement;
|
||||
@@ -141,7 +141,7 @@ export class DocViewerComponent implements OnDestroy {
|
||||
} else {
|
||||
// Security: `doc.contents` is always authored by the documentation team
|
||||
// and is considered to be safe.
|
||||
this.nextViewContainer.innerHTML = unwrapHtmlForSink(doc.contents);
|
||||
this.nextViewContainer.innerHTML = unwrapHtml(doc.contents) as string;
|
||||
}
|
||||
}),
|
||||
tap(() => addTitleAndToc = this.prepareTitleAndToc(this.nextViewContainer, doc.id)),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
|
||||
import { scriptUrl, unwrapScriptUrlForSink } from 'safevalues';
|
||||
import { trustedResourceUrl, unwrapResourceUrl } from 'safevalues';
|
||||
|
||||
import { formatErrorEventForAnalytics } from './analytics-format-error';
|
||||
import { WindowToken } from '../shared/window';
|
||||
@@ -82,7 +82,7 @@ export class AnalyticsService {
|
||||
private _installGlobalSiteTag() {
|
||||
const window = this.window;
|
||||
const url: TrustedScriptURL =
|
||||
scriptUrl`https://www.googletagmanager.com/gtag/js?id=${environment.googleAnalyticsId}`;
|
||||
trustedResourceUrl`https://www.googletagmanager.com/gtag/js?id=${environment.googleAnalyticsId}`;
|
||||
|
||||
// Note: This cannot be an arrow function as `gtag.js` expects an actual `Arguments`
|
||||
// instance with e.g. `callee` to be set. Do not attempt to change this and keep this
|
||||
@@ -103,7 +103,7 @@ export class AnalyticsService {
|
||||
|
||||
const el = window.document.createElement('script');
|
||||
el.async = true;
|
||||
el.src = unwrapScriptUrlForSink(url);
|
||||
el.src = unwrapResourceUrl(url) as string;
|
||||
window.document.head.appendChild(el);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { ErrorHandler } from '@angular/core';
|
||||
import { MatIconRegistry } from '@angular/material/icon';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { unwrapHtmlForSink } from 'safevalues';
|
||||
import { unwrapHtml } from 'safevalues';
|
||||
import { concatHtmls } from 'safevalues/builders/html_builders';
|
||||
import { CustomIconRegistry, SvgIconInfo } from './custom-icon-registry';
|
||||
import { svg } from './security';
|
||||
@@ -69,6 +69,6 @@ describe('CustomIconRegistry', () => {
|
||||
|
||||
function createSvg(svgSrc: TrustedHTML): SVGElement {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = unwrapHtmlForSink(svgSrc);
|
||||
div.innerHTML = unwrapHtml(svgSrc) as string;
|
||||
return div.querySelector('svg') as SVGElement;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { of } from 'rxjs';
|
||||
import { MatIconRegistry } from '@angular/material/icon';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { unwrapHtmlForSink } from 'safevalues';
|
||||
import { unwrapHtml } from 'safevalues';
|
||||
|
||||
/**
|
||||
* Use SVG_ICONS (and SvgIconInfo) as "multi" providers to provide the SVG source
|
||||
@@ -76,7 +76,7 @@ export class CustomIconRegistry extends MatIconRegistry {
|
||||
const div = document.createElement('DIV');
|
||||
|
||||
// SECURITY: the source for the SVG icons is provided in code by trusted developers
|
||||
div.innerHTML = unwrapHtmlForSink(svgIcon.svgSource);
|
||||
div.innerHTML = unwrapHtml(svgIcon.svgSource) as string;
|
||||
|
||||
const svgElement = div.querySelector('svg') as SVGElement;
|
||||
nsIconMap[svgIcon.name] = svgElement;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { htmlFromStringKnownToSatisfyTypeContract } from 'safevalues/unsafe/reviewed';
|
||||
import { htmlSafeByReview } from 'safevalues/restricted/reviewed';
|
||||
|
||||
export function fromInnerHTML(el: Element): TrustedHTML {
|
||||
// SECURITY: Existing innerHTML content is already trusted.
|
||||
return htmlFromStringKnownToSatisfyTypeContract(el.innerHTML, '^');
|
||||
return htmlSafeByReview(el.innerHTML, '^');
|
||||
}
|
||||
|
||||
export function fromOuterHTML(el: Element): TrustedHTML {
|
||||
// SECURITY: Existing outerHTML content is already trusted.
|
||||
return htmlFromStringKnownToSatisfyTypeContract(el.outerHTML, '^');
|
||||
return htmlSafeByReview(el.outerHTML, '^');
|
||||
}
|
||||
|
||||
export function svg(constantSvg: TemplateStringsArray): TrustedHTML {
|
||||
// SECURITY: Template literal argument with no interpolation is constant, and
|
||||
// hence trusted.
|
||||
return htmlFromStringKnownToSatisfyTypeContract(constantSvg[0], '^');
|
||||
return htmlSafeByReview(constantSvg[0], '^');
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Inject, Injectable } from '@angular/core';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
import { ScrollSpyInfo, ScrollSpyService } from 'app/shared/scroll-spy.service';
|
||||
import { unwrapHtmlForSink } from 'safevalues';
|
||||
import { unwrapHtml } from 'safevalues';
|
||||
import { fromInnerHTML } from './security';
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ export class TocService {
|
||||
// - Mark the HTML as trusted to be used with `[innerHTML]`.
|
||||
private extractHeadingSafeHtml(heading: HTMLHeadingElement) {
|
||||
const div: HTMLDivElement = this.document.createElement('div');
|
||||
div.innerHTML = unwrapHtmlForSink(fromInnerHTML(heading));
|
||||
div.innerHTML = unwrapHtml(fromInnerHTML(heading)) as string;
|
||||
|
||||
// Remove any `.github-links` or `.header-link` elements (along with their content).
|
||||
div.querySelectorAll('.github-links, .header-link').forEach(link => link.remove());
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
// scope.
|
||||
|
||||
import { of } from 'rxjs';
|
||||
import { unwrapHtmlForSink } from 'safevalues';
|
||||
import { htmlFromStringKnownToSatisfyTypeContract } from 'safevalues/unsafe/reviewed';
|
||||
import { unwrapHtml } from 'safevalues';
|
||||
import { htmlSafeByReview } from 'safevalues/restricted/reviewed';
|
||||
|
||||
export class MockPrettyPrinter {
|
||||
formatCode(code: TrustedHTML, language?: string, linenums?: number | boolean) {
|
||||
const linenumsStr = (linenums === undefined) ? '' : `, linenums: ${linenums}`;
|
||||
return of(htmlFromStringKnownToSatisfyTypeContract(
|
||||
return of(htmlSafeByReview(
|
||||
`Formatted code (language: ${language || 'auto'}${linenumsStr}): ${
|
||||
unwrapHtmlForSink(code)}`,
|
||||
unwrapHtml(code)}`,
|
||||
'safe transformation of existing TrustedHTML'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,6 +205,7 @@
|
||||
/guide/displaying-data --> /start#template-syntax
|
||||
/guide/i18n --> /guide/i18n-overview
|
||||
/guide --> /docs
|
||||
/guide/ivy --> https://v12.angular.io/guide/ivy
|
||||
/guide/learning-angular --> /start
|
||||
/guide/learning-angular.html --> /start
|
||||
/guide/metadata --> /guide/aot-compiler
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
# Angular documentation lint tool
|
||||
|
||||
The files in this directory support the [Vale][ValeMain] documentation lint tool for use while you edit [angular.io][AioMain] documentation files.
|
||||
|
||||
*Linting* is an automated process that lint tools, or *linters*, perform to identify stylistic errors in program source code.
|
||||
Vale is a lint tool that performs a similar analysis of documentation source code.
|
||||
For more information about lint tools, linting, and their history, see [*Lint* in Wikipedia][WikipediaWikiLintSoftware].
|
||||
|
||||
## Use Vale to lint your documentation
|
||||
|
||||
[Vale][ValeMain] is an open source, command-line tool that reviews writing style and phrases in your documentation.
|
||||
You can add it to your integrated development environment \(IDE\) or code editor to test your documentation edits before you submit your pull request.
|
||||
Using it can help improve the documentation's readability and the consistency of terminology and voice across a range of topics and contributors.
|
||||
|
||||
The lint tool is helpful and has been tailored to the Angular documentation style guide.
|
||||
Unfortunately, it is not as powerful as the grammar and spelling features you find in contemporary document editors.
|
||||
While Vale helps, it doesn't replace the reviewers that you're currently using to help you write great documentation.
|
||||
|
||||
**To use Vale in your documentation:**
|
||||
|
||||
1. [Install Vale][AioToolsDocLinterReadmeInstallValeInYourVsCodeIde] in your Visual Studio Code IDE.
|
||||
To install and use Vale in a different IDE, see [Installation][ValeDocsValeCliInstallation].
|
||||
2. Fix the problems that Vale identifies in your IDE.
|
||||
|
||||
Log any problem you encounter with the documentation linter as a [new docs issue][GithubAngularAngularIssuesNewAssigneesLabelsTemplate3DocsBugYaml] in the repo.
|
||||
Be sure to specify that this is a linter issue in your description.
|
||||
|
||||
## Fix documentation problems identified by Vale
|
||||
|
||||
Vale evaluates a markdown \(`.md`\) file when you open it in the IDE and each time you save it. Vale does not review your document as you make changes in it.
|
||||
|
||||
When Vale identifies a problem, it can take a simple word substitution or rewriting several sentences or paragraphs to fix it.
|
||||
Sometimes, you might need to take a step back from the text and consider other alternatives.
|
||||
|
||||
To find the best way to fix a problem that Vale identified, think of your reader, be flexible, and keep an open mind.
|
||||
The documentation should be understood by a range of readers, some of whom might not have much experience with Angular or even web development.
|
||||
|
||||
> **Note**
|
||||
> Remember that when a developer is reading documentation, they are often doing so while thinking about other things, such as coding their Angular application.
|
||||
> Keeping the docs easy to read, helps developers concentrate on their coding.
|
||||
|
||||
These are some tips to help you resolve the issues that the lint tool identifies and to help you make your docs easier to read.
|
||||
|
||||
### Refer to the style guides
|
||||
|
||||
The lint tool tests against the styles found in these style guides.
|
||||
Most style tests include links to relevant sections in these documents for more information.
|
||||
|
||||
* [Angular documentation style guide][AioGuideDocsStyleGuide]
|
||||
* [Google Developer Documentation Style Guide][GoogleDevelopersStyle]
|
||||
|
||||
> **Note**
|
||||
> Not every style mentioned in the style guides has a test.
|
||||
> Style guides and the style tests can change.
|
||||
|
||||
### Split up long sentences
|
||||
|
||||
Generally, shorter sentences are easier to read than longer ones.
|
||||
Long sentences can occur when you try to say too much at once.
|
||||
Long sentences, as well as the use of parentheses, semi-colons, or words identified as *too-wordy*, generally require rethinking and rewriting.
|
||||
Consider restructuring a long sentence to break its individual ideas into distinct sentences or bullet points.
|
||||
|
||||
### Use lists and tables
|
||||
|
||||
Sentences that contain comma-separated lists might be clearer if presented as a bulleted-list or table.
|
||||
Consider changing a comma-separated list of items in a sentence to a list of bullets to make those list items easier to read.
|
||||
|
||||
### Use more common words
|
||||
|
||||
Shorter, more common words are generally easier to read than longer ones.
|
||||
This does not mean you need to write down to the audience. Technical docs should still be precise.
|
||||
Angular docs are read by many people around the world and should use language that the most people can understand.
|
||||
|
||||
If you think a specific term is required even though it is been flagged as uncommon, try to include a short explanation of the term.
|
||||
Also, try adding some context around its first mention.
|
||||
Linking a term to another section or definition is also an option, but consider the disruption that causes to the reader before you use it.
|
||||
If you force a reader to go to another page for a definition, they might lose their concentration on the current topic and their primary goal.
|
||||
|
||||
### Use fewer words
|
||||
|
||||
If you can remove a word and not lose the meaning of the sentence, leave it out.
|
||||
|
||||
One common place where removing words can help is in a list of examples with more than two or three items.
|
||||
Before you place the items in a bullet list, consider if only one of the items can convey the desired meaning.
|
||||
Another option might be to replace a list of items with a single term that describes all the elements in your list.
|
||||
|
||||
### If all else fails
|
||||
|
||||
The style rules generally guide you in the direction of clearer content, but sometimes you might need to break the rules.
|
||||
If you decide that the best choice for the text conflicts with the linter, mark the text as an exception to linting.
|
||||
|
||||
If you use these exceptions, please limit the amount of text that you exclude from analysis to the fewest lines possible.
|
||||
|
||||
When necessary, you can apply these exceptions to your content.
|
||||
|
||||
1. **General exception**
|
||||
|
||||
A *general exception* allows you to exclude the specified text from all lint testing.
|
||||
|
||||
To apply a general exception, surround the text that you do not want the linter to test with the HTML
|
||||
`comment` elements shown in this example.
|
||||
|
||||
```markdown
|
||||
|
||||
<!-- vale off -->
|
||||
|
||||
Text the linter does not check for any style problem.
|
||||
|
||||
<!-- vale on -->
|
||||
|
||||
```
|
||||
|
||||
Be sure to leave a blank line before and after each comment.
|
||||
|
||||
2. **Style exception**
|
||||
|
||||
A *style exception* allows you to exclude text from an individual style test.
|
||||
|
||||
To apply a style exception, surround the text that you do not want the linter to test with these HTML
|
||||
`comment` elements. Between these comments, the linter ignores the style test in the comment, but
|
||||
still tests for all other styles that are in use.
|
||||
|
||||
```markdown
|
||||
<!-- vale Style.Rule = NO -->
|
||||
<!-- vale Style.Rule = YES -->
|
||||
```
|
||||
|
||||
Replace `Style.Rule` in the comments with the style and rule from the problem message displayed in the IDE.
|
||||
For example, imagine that you got this problem message and you want to use the word it identified as a problem.
|
||||
|
||||
```markdown
|
||||
Did you really mean 'inlines'? It was not found in our dictionary. Vale(Angular.Angular_Spelling) [Ln 24, Col 59]
|
||||
```
|
||||
|
||||
The `Style.Rule` for this message is the text inside the parentheses: `Angular.Angular_Spelling` in this case.
|
||||
To turn off that style test, use the comments shown in this example.
|
||||
|
||||
```markdown
|
||||
|
||||
<!-- vale Angular.Angular_Spelling = NO -->
|
||||
|
||||
'inlines' does not display a problem because the linter does not spell check this text.
|
||||
|
||||
Remember that the linter does not catch any other spelling errors in this block of text.
|
||||
|
||||
The linter continues to test all other style rules.
|
||||
|
||||
<!-- vale Angular.Angular_Spelling = YES -->
|
||||
|
||||
```
|
||||
|
||||
## Install Vale on your development system
|
||||
|
||||
Complete these procedures to install the Vale documentation linter on your development system.
|
||||
|
||||
Vale can be installed on Windows, macOS, and Linux, and it can be integrated into many IDEs.
|
||||
The instructions for installing it into Visual Studio Code on Windows and macOS are summarized here.
|
||||
For more information, or to install Vale in another IDE or on another operating system, see [Vale installation documentation][ValeDocsValeCliInstallation].
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before you proceed, make sure that:
|
||||
|
||||
1. You have cloned the [`angular/angular` repo][GithubAngularAngular] on your system. You can work in a fork of the `angular/angular` repo,
|
||||
but it's easier if your Vale installation uses an up-to-date clone of the `angular/angular` repo.
|
||||
2. You have a development or writing environment for `angular.io` in the `angular/angular` repo and you can build the `angular.io` docs.
|
||||
For information about how to create the authoring environment for `angular.io`, see [Angular documentation project][GithubAngularAngularTreeMainAioAngularDocumentationProjectHttpsangulario].
|
||||
3. You have the required package manager installed on your system. If not, install it before continuing.
|
||||
* [homebrew][BrewMain] on your macOS system.
|
||||
* [chocolatey][Chocolatey] on your Windows system.
|
||||
|
||||
### Install the Vale command-line tool
|
||||
|
||||
Open the following tools on your development system.
|
||||
|
||||
1. Open a command-line tool:
|
||||
* `terminal` on macOS, for example
|
||||
* `Windows PowerShell` on Windows
|
||||
2. Open Visual Studio Code.
|
||||
|
||||
Follow the instructions for the OS on your development system.
|
||||
To install Vale on a different OS, see [Installation][ValeDocsValeCliInstallation].
|
||||
|
||||
#### Install Vale on macOS
|
||||
|
||||
In your command-line tool:
|
||||
|
||||
<!-- vale Angular.WriteGood_Illusions = NO -->
|
||||
<!-- vale Angular.Angular_CliReference = NO -->
|
||||
|
||||
1. Run `brew install vale` to install Vale.
|
||||
2. Get the path to the `vale` application to use as the value of the **Vale > Vale CLI : Path** setting.
|
||||
1. In the command-line tool, run `which vale`.
|
||||
Save the returned path for use in the next procedure.
|
||||
|
||||
2. If this command does not return a path, restart macOS and repeat this step.
|
||||
3. Get the path to the configuration file, `vale.ini`, to use in the **Vale > Vale CLI : Config** setting.
|
||||
1. In the command-line tool, navigate to your `git` working directory with the `angular/angular` repo.
|
||||
2. Run `git pull` to update the repo.
|
||||
3. In your clone of the `angular/angular` repo, navigate to the `aio/tools/doc-linter` directory.
|
||||
4. In the `aio/tools/doc-linter` directory, confirm that you have the `vale.ini` file.
|
||||
5. Run `pwd` to get the full path to `vale.ini` to use in the next procedure.
|
||||
|
||||
<!-- vale Angular.Angular_CliReference = YES -->
|
||||
<!-- vale Angular.WriteGood_Illusions = YES -->
|
||||
|
||||
#### Install Vale on Windows
|
||||
|
||||
In your command-line tool:
|
||||
|
||||
<!-- vale Angular.WriteGood_Illusions = NO -->
|
||||
<!-- vale Angular.Angular_CliReference = NO -->
|
||||
|
||||
1. Run `choco install vale` to install Vale.
|
||||
2. Get the path to the `vale` application to use as the value of the **Vale > Vale CLI : Path** setting.
|
||||
1. In the command-line tool, run `where vale.exe`.
|
||||
Save the returned path for use in the next procedure.
|
||||
|
||||
2. If this command does not return a path, restart Windows and repeat this step.
|
||||
3. Get the path to the configuration file, `vale.ini`, to use in the **Vale > Vale CLI : Config** setting.
|
||||
1. In the command-line tool, navigate to your `git` working directory with the `angular/angular` repo.
|
||||
2. Run `git pull` to update the repo.
|
||||
3. In your clone of the `angular/angular` repo, navigate to the `aio\tools\doc-linter` directory.
|
||||
4. In the `aio\tools\doc-linter` directory, confirm that you have the `vale.ini` file.
|
||||
5. Run `cd` to get the full path to `vale.ini` to use in the next procedure.
|
||||
|
||||
<!-- vale Angular.Angular_CliReference = YES -->
|
||||
<!-- vale Angular.WriteGood_Illusions = YES -->
|
||||
|
||||
### Install the Vale extension for Visual Studio Code
|
||||
|
||||
This procedure is the same for macOS and Windows.
|
||||
To install Vale in a different IDE, see [Installation][ValeDocsValeCliInstallation].
|
||||
|
||||
<!-- vale Angular.WriteGood_Illusions = NO -->
|
||||
<!-- vale Angular.Angular_CliReference = NO -->
|
||||
|
||||
**To install and configure the Visual Studio Code Vale extension:**
|
||||
|
||||
1. In Visual Studio Code, go to the **Extensions** pane.
|
||||
2. In the Visual Studio Code **Extensions** pane:
|
||||
1. In the search box, enter `Vale`.
|
||||
2. In the Vale extension entry, choose, **Install**.
|
||||
3. Access the settings in Visual Studio Code for the Vale extension.
|
||||
* On macOS, in the **Code** menu, choose **Preferences**, and then choose **Settings**.
|
||||
* On Windows, in the **File** menu, choose **Preferences**, and then choose **Settings**.
|
||||
4. In the **User** settings, navigate to **Extensions > Vale**.
|
||||
5. Update the Vale extension settings as shown.
|
||||
* **Vale : Config**, enter the full path to `vale.ini` from the preceding procedure and append the `vale.ini` filename.
|
||||
* **Vale : Min Alert Level**, choose `inherited` or `suggestion`.
|
||||
* **Vale : Path**, enter the full path of the `vale` application that `which vale` or `where vale.exe` returned in a preceding step.
|
||||
6. Restart Visual Studio Code to apply the new settings.
|
||||
|
||||
<!-- vale Angular.Angular_CliReference = YES -->
|
||||
<!-- vale Angular.WriteGood_Illusions = YES -->
|
||||
|
||||
### Known issues with the Visual Studio Code extension
|
||||
|
||||
If you're having problems with the `0.15.0` version of the Vale extension to Visual Studio Code, try:
|
||||
|
||||
1. Uninstalling version `0.15.0` of the Vale extension.
|
||||
2. Installing version `0.14.2` of the Vale extension.
|
||||
|
||||
If you're using version `0.14.2`, the Vale extension settings to use are:
|
||||
|
||||
<!-- vale Angular.WriteGood_Illusions = NO -->
|
||||
<!-- vale Angular.Angular_CliReference = NO -->
|
||||
|
||||
* **Vale > Core : Use CLI**, checked.
|
||||
* **Vale > Server : Lint Context**, `0`.
|
||||
* **Vale > Server : Provide Fixes**, unchecked.
|
||||
* **Vale > Server : Server URL**, leave empty.
|
||||
* **Vale > Vale CLI : Config**, enter the full path to `vale.ini` from the preceding procedure and append the `vale.ini` filename.
|
||||
* **Vale > Vale CLI : Min Alert Level**, choose `inherited` or `suggestion`.
|
||||
* **Vale > Vale CLI : Path**, enter the full path of the `vale` application that `which vale` or `where vale.exe` returned in a preceding step.
|
||||
|
||||
<!-- vale Angular.Angular_CliReference = YES -->
|
||||
<!-- vale Angular.WriteGood_Illusions = YES -->
|
||||
|
||||
## Update the Vale command-line tool
|
||||
|
||||
* To update Vale on macOS to the latest version, in your command-line tool, run `brew upgrade vale`.
|
||||
|
||||
* To update Vale on Windows to the latest version, in a PowerShell window, run `choco update vale`.
|
||||
|
||||
## Update the Vale style tests
|
||||
|
||||
The style tests are stored in your local clone of the [`angular/angular` repo][GithubAngularAngular] and
|
||||
are updated automatically when you pull the latest code to your system.
|
||||
If you're using another branch or fork of the `angular/angular` repo, be sure to also update that branch or fork.
|
||||
|
||||
<!-- links -->
|
||||
|
||||
[AioGuideDocsStyleGuide]: https://angular.io/guide/docs-style-guide "Angular documentation style guide | Angular"
|
||||
|
||||
[AioMain]: https://angular.io "Angular"
|
||||
|
||||
[AioToolsDocLinterReadmeInstallValeInYourVsCodeIde]: #install-vale-on-your-development-system "Install Vale | "
|
||||
|
||||
<!-- external links -->
|
||||
|
||||
[BrewMain]: https://brew.sh "homebrew"
|
||||
|
||||
[Chocolatey]: https://chocolatey.org/ "Chocolatey"
|
||||
|
||||
[GithubAngularAngular]: https://github.com/angular/angular "angular/angular | GitHub"
|
||||
|
||||
[GithubAngularAngularIssuesNewAssigneesLabelsTemplate3DocsBugYaml]: https://github.com/angular/angular/issues/new?assignees=&labels=&template=3-docs-bug.yaml "Issue: Docs or angular.io Bug Report | angular/angular | GitHub"
|
||||
|
||||
[GithubAngularAngularTreeMainAioAngularDocumentationProjectHttpsangulario]: https://github.com/angular/angular/tree/main/aio#angular-documentation-project-httpsangulario "Angular documentation project [AioMain] | angular/angular/aio | GitHub"
|
||||
|
||||
[GoogleDevelopersStyle]: https://developers.google.com/style "About this guide | Google developer documentation style guide | Google Developers"
|
||||
|
||||
[ValeDocsValeCliInstallation]: https://vale.sh/docs/vale-cli/installation "Installation | Vale.sh"
|
||||
|
||||
[ValeMain]: https://vale.sh "Vale.sh"
|
||||
|
||||
[WikipediaWikiLintSoftware]: https://en.wikipedia.org/wiki/Lint_%28software%29 "Lint (software) | Wikipedia"
|
||||
|
||||
<!-- end links -->
|
||||
|
||||
<!-- @reviewed 2022-07-15 -->
|
||||
@@ -0,0 +1,205 @@
|
||||
SET UTF-8
|
||||
TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ'
|
||||
ICONV 1
|
||||
ICONV ’ '
|
||||
NOSUGGEST !
|
||||
|
||||
# ordinal numbers
|
||||
COMPOUNDMIN 1
|
||||
# only in compounds: 1th, 2th, 3th
|
||||
ONLYINCOMPOUND c
|
||||
# compound rules:
|
||||
# 1. [0-9]*1[0-9]th (10th, 11th, 12th, 56714th, etc.)
|
||||
# 2. [0-9]*[02-9](1st|2nd|3rd|[4-9]th) (21st, 22nd, 123rd, 1234th, etc.)
|
||||
COMPOUNDRULE 2
|
||||
COMPOUNDRULE n*1t
|
||||
COMPOUNDRULE n*mp
|
||||
WORDCHARS 0123456789
|
||||
|
||||
PFX A Y 1
|
||||
PFX A 0 re .
|
||||
|
||||
PFX I Y 1
|
||||
PFX I 0 in .
|
||||
|
||||
PFX U Y 1
|
||||
PFX U 0 un .
|
||||
|
||||
PFX C Y 1
|
||||
PFX C 0 de .
|
||||
|
||||
PFX E Y 1
|
||||
PFX E 0 dis .
|
||||
|
||||
PFX F Y 1
|
||||
PFX F 0 con .
|
||||
|
||||
PFX K Y 1
|
||||
PFX K 0 pro .
|
||||
|
||||
SFX V N 2
|
||||
SFX V e ive e
|
||||
SFX V 0 ive [^e]
|
||||
|
||||
SFX N Y 3
|
||||
SFX N e ion e
|
||||
SFX N y ication y
|
||||
SFX N 0 en [^ey]
|
||||
|
||||
SFX X Y 3
|
||||
SFX X e ions e
|
||||
SFX X y ications y
|
||||
SFX X 0 ens [^ey]
|
||||
|
||||
SFX H N 2
|
||||
SFX H y ieth y
|
||||
SFX H 0 th [^y]
|
||||
|
||||
SFX Y Y 1
|
||||
SFX Y 0 ly .
|
||||
|
||||
SFX G Y 2
|
||||
SFX G e ing e
|
||||
SFX G 0 ing [^e]
|
||||
|
||||
SFX J Y 2
|
||||
SFX J e ings e
|
||||
SFX J 0 ings [^e]
|
||||
|
||||
SFX D Y 4
|
||||
SFX D 0 d e
|
||||
SFX D y ied [^aeiou]y
|
||||
SFX D 0 ed [^ey]
|
||||
SFX D 0 ed [aeiou]y
|
||||
|
||||
SFX T N 4
|
||||
SFX T 0 st [eg]
|
||||
SFX T y iest [^aeiou]y
|
||||
SFX T 0 est [aeiou]y
|
||||
SFX T 0 est [^ey]
|
||||
|
||||
SFX R Y 4
|
||||
SFX R 0 r e
|
||||
SFX R y ier [^aeiou]y
|
||||
SFX R 0 er [aeiou]y
|
||||
SFX R 0 er [^ey]
|
||||
|
||||
SFX Z Y 4
|
||||
SFX Z 0 rs e
|
||||
SFX Z y iers [^aeiou]y
|
||||
SFX Z 0 ers [aeiou]y
|
||||
SFX Z 0 ers [^ey]
|
||||
|
||||
SFX S Y 4
|
||||
SFX S y ies [^aeiou]y
|
||||
SFX S 0 s [aeiou]y
|
||||
SFX S 0 es [sxzh]
|
||||
SFX S 0 s [^sxzhy]
|
||||
|
||||
SFX P Y 3
|
||||
SFX P y iness [^aeiou]y
|
||||
SFX P 0 ness [aeiou]y
|
||||
SFX P 0 ness [^y]
|
||||
|
||||
SFX M Y 1
|
||||
SFX M 0 's .
|
||||
|
||||
SFX B Y 3
|
||||
SFX B 0 able [^aeiou]
|
||||
SFX B 0 able ee
|
||||
SFX B e able [^aeiou]e
|
||||
|
||||
SFX L Y 1
|
||||
SFX L 0 ment .
|
||||
|
||||
REP 90
|
||||
REP a ei
|
||||
REP ei a
|
||||
REP a ey
|
||||
REP ey a
|
||||
REP ai ie
|
||||
REP ie ai
|
||||
REP alot a_lot
|
||||
REP are air
|
||||
REP are ear
|
||||
REP are eir
|
||||
REP air are
|
||||
REP air ere
|
||||
REP ere air
|
||||
REP ere ear
|
||||
REP ere eir
|
||||
REP ear are
|
||||
REP ear air
|
||||
REP ear ere
|
||||
REP eir are
|
||||
REP eir ere
|
||||
REP ch te
|
||||
REP te ch
|
||||
REP ch ti
|
||||
REP ti ch
|
||||
REP ch tu
|
||||
REP tu ch
|
||||
REP ch s
|
||||
REP s ch
|
||||
REP ch k
|
||||
REP k ch
|
||||
REP f ph
|
||||
REP ph f
|
||||
REP gh f
|
||||
REP f gh
|
||||
REP i igh
|
||||
REP igh i
|
||||
REP i uy
|
||||
REP uy i
|
||||
REP i ee
|
||||
REP ee i
|
||||
REP j di
|
||||
REP di j
|
||||
REP j gg
|
||||
REP gg j
|
||||
REP j ge
|
||||
REP ge j
|
||||
REP s ti
|
||||
REP ti s
|
||||
REP s ci
|
||||
REP ci s
|
||||
REP k cc
|
||||
REP cc k
|
||||
REP k qu
|
||||
REP qu k
|
||||
REP kw qu
|
||||
REP o eau
|
||||
REP eau o
|
||||
REP o ew
|
||||
REP ew o
|
||||
REP oo ew
|
||||
REP ew oo
|
||||
REP ew ui
|
||||
REP ui ew
|
||||
REP oo ui
|
||||
REP ui oo
|
||||
REP ew u
|
||||
REP u ew
|
||||
REP oo u
|
||||
REP u oo
|
||||
REP u oe
|
||||
REP oe u
|
||||
REP u ieu
|
||||
REP ieu u
|
||||
REP ue ew
|
||||
REP ew ue
|
||||
REP uff ough
|
||||
REP oo ieu
|
||||
REP ieu oo
|
||||
REP ier ear
|
||||
REP ear ier
|
||||
REP ear air
|
||||
REP air ear
|
||||
REP w qu
|
||||
REP qu w
|
||||
REP z ss
|
||||
REP ss z
|
||||
REP shun tion
|
||||
REP shun sion
|
||||
REP shun cion
|
||||
REP size cise
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
# tests for <img> elements without alt attribute
|
||||
extends: existence
|
||||
message: '<img> elements need the alt attribute to be the first attribute.'
|
||||
link: https://angular.io/guide/docs-style-guide#images
|
||||
level: error
|
||||
scope: raw
|
||||
raw:
|
||||
- '<img (?!alt=)[^\>]+>'
|
||||
@@ -0,0 +1,8 @@
|
||||
# tests for blank lines after an HTML tag or tag group
|
||||
extends: existence
|
||||
message: 'HTML in the Markdown should be followed by a blank line.'
|
||||
link: https://angular.io/guide/docs-style-guide#markdown-and-html
|
||||
level: error
|
||||
scope: raw
|
||||
raw:
|
||||
- '[\r\n]\<.+\>[\r\n](?!(\s*[\r\n\<]))'
|
||||
@@ -0,0 +1,8 @@
|
||||
# tests for blank lines before an HTML tag or tag group
|
||||
extends: existence
|
||||
message: 'HTML in the Markdown should be preceded by a blank line.'
|
||||
link: https://angular.io/guide/docs-style-guide#markdown-and-html
|
||||
level: error
|
||||
scope: raw
|
||||
raw:
|
||||
- '(?<![\r\n\>])[\r\n]\<.+\>[\r\n]'
|
||||
@@ -0,0 +1,8 @@
|
||||
# code and CLI references that should be marked as code
|
||||
extends: existence
|
||||
message: 'Clarify if this refers to a specific CLI, a specific ng command, or a command-line tool.'
|
||||
link: 'https://angular.io/guide/glossary#command-line-interface-cli'
|
||||
ignorecase: false
|
||||
level: warning
|
||||
tokens:
|
||||
- '((?<!Angular )CLI(?! [B|b]uilder))'
|
||||
@@ -0,0 +1,8 @@
|
||||
# tests for strings qualified by back-ticks are surrounded by spaces or punctuation
|
||||
extends: existence
|
||||
message: 'The code term should be followed by a space or punctuation.'
|
||||
link: https://angular.io/guide/docs-style-guide#when-to-use-code-font
|
||||
level: error
|
||||
scope: raw
|
||||
tokens:
|
||||
- '\s\x60[^\x60]+\x60[^ .;\n\r]'
|
||||
@@ -0,0 +1,8 @@
|
||||
# code and CLI references that should be marked as code
|
||||
extends: existence
|
||||
message: "If '%s' is a code reference, make sure it's marked correctly."
|
||||
link: 'https://developers.google.com/style/code-in-text'
|
||||
scope: sentence
|
||||
ignorecase: false
|
||||
level: suggestion
|
||||
tokens: (ng [a-z]+)
|
||||
@@ -0,0 +1,17 @@
|
||||
# Inclusuve language tested by Angular CI/CD
|
||||
# tests for strings that must be replaced before the content is published
|
||||
extends: substitution
|
||||
message: "Use '%s' instead of '%s'."
|
||||
link: 'https://developers.google.com/style/word-list'
|
||||
level: error
|
||||
ignorecase: true
|
||||
action:
|
||||
name: replace
|
||||
swap:
|
||||
master: primary|main|leader|active|writer
|
||||
slave: secondary|node|worker|replica|passive
|
||||
'white[\s_-]*list': include list|allow list
|
||||
'black[\s_-]*list': exclude list|deny list
|
||||
grandfathered: legacied|exempted
|
||||
'sanity[\s_-]*check': confidence check
|
||||
'man[\s_-]*hours': person-hours|human-hours
|
||||
@@ -0,0 +1,11 @@
|
||||
# tests for NOTE strings that are not bolded
|
||||
extends: existence
|
||||
message: 'Alert heading must be bold.'
|
||||
link: https://angular.io/guide/docs-style-guide#alerts-and-callouts
|
||||
level: error
|
||||
ignorecase: false
|
||||
scope: raw
|
||||
raw:
|
||||
- (?<!\*\*)NOTE[^\*]*(?!\*\*)
|
||||
- (?<!\*\*)TIP[^\*]*(?!\*\*)
|
||||
- (?<!\*\*)IMPORTANT[^\*]*(?!\*\*)
|
||||
@@ -0,0 +1,7 @@
|
||||
extends: occurrence
|
||||
message: 'Try to keep your sentences shorter than 26 words. Shorter sentences tend to be easier to read.'
|
||||
link: https://developers.google.com/style/accessibility#ease-of-reading
|
||||
level: suggestion
|
||||
scope: sentence
|
||||
max: 26
|
||||
token: '[\w-]+'
|
||||
@@ -0,0 +1,11 @@
|
||||
# Uses the built-in dictionary and filters.
|
||||
extends: spelling
|
||||
dicpath: ../../dictionaries/en_us/
|
||||
message: "Did you really mean '%s'? It wasn't found in our dictionary."
|
||||
level: warning
|
||||
ignore:
|
||||
- Vocab/Angular.txt # Angular terms
|
||||
- Vocab/Foreign.txt # Foreign language words used in the text
|
||||
- Vocab/Jargon.txt # Computer jargon
|
||||
- Vocab/Names.txt # Names of people, products, and things
|
||||
- Vocab/Web.txt # Web terms
|
||||
@@ -0,0 +1,8 @@
|
||||
# tests for TODO in HTML comments in the markdown
|
||||
extends: existence
|
||||
message: 'ToDo comments make the docs look unfinished. Consider removing them before you publish.'
|
||||
link: https://angular.io/guide/docs-style-guide#when-to-use-code-font
|
||||
level: suggestion
|
||||
scope: raw
|
||||
raw:
|
||||
- '\<\!\-\-[\s]*[Tt][Oo][Dd][Oo][^>]*\-\-\>'
|
||||
@@ -0,0 +1,9 @@
|
||||
# tests for TODO in text when NOT used in a sentence
|
||||
extends: existence
|
||||
message: 'Remove %s before publishing.'
|
||||
link: https://angular.io/guide/docs-style-guide#when-to-use-code-font
|
||||
level: error
|
||||
ignorecase: true
|
||||
scope: sentence
|
||||
raw:
|
||||
- (?<!\s)[Tt][Oo][Dd][Oo](?!\s)
|
||||
@@ -0,0 +1,10 @@
|
||||
# adapted from Google style library
|
||||
extends: existence
|
||||
message: "Use 'AM' or 'PM' and precede it with a space."
|
||||
link: 'https://developers.google.com/style/word-list'
|
||||
level: error
|
||||
nonword: true
|
||||
tokens:
|
||||
- '\d{1,2}[AP]M'
|
||||
- '\d{1,2} ?[ap]m'
|
||||
- '\d{1,2} ?[aApP]\.[mM]\.'
|
||||
@@ -0,0 +1,66 @@
|
||||
# adapted from Google style library
|
||||
extends: conditional
|
||||
message: "Spell out '%s', if it's unfamiliar to the audience."
|
||||
link: 'https://developers.google.com/style/abbreviations'
|
||||
level: suggestion
|
||||
ignorecase: false
|
||||
# Ensures that the existence of 'first' implies the existence of 'second'.
|
||||
first: '\b([A-Z]{3,5})\b'
|
||||
second: '(?:\b[A-Z][\w\- ]+ )+\(([A-Z]{3,5})\)'
|
||||
# ... with the exception of these:
|
||||
exceptions:
|
||||
- API
|
||||
- ASP
|
||||
- CLI
|
||||
- CPU
|
||||
- CSS
|
||||
- CSV
|
||||
- DEBUG
|
||||
- DOM
|
||||
- DPI
|
||||
- FAQ
|
||||
- GCC
|
||||
- GDB
|
||||
- GET
|
||||
- GPU
|
||||
- GTK
|
||||
- GUI
|
||||
- HTML
|
||||
- HTTP
|
||||
- HTTPS
|
||||
- IDE
|
||||
- JAR
|
||||
- JSON
|
||||
- JSX
|
||||
- LESS
|
||||
- LLDB
|
||||
- NET
|
||||
- NOTE
|
||||
- NVDA
|
||||
- OSS
|
||||
- PATH
|
||||
- PDF
|
||||
- PHP
|
||||
- POST
|
||||
- RAM
|
||||
- REPL
|
||||
- RSA
|
||||
- SCM
|
||||
- SCSS
|
||||
- SDK
|
||||
- SQL
|
||||
- SSH
|
||||
- SSL
|
||||
- SVG
|
||||
- TBD
|
||||
- TCP
|
||||
- TIP
|
||||
- TODO
|
||||
- URI
|
||||
- URL
|
||||
- USB
|
||||
- UTF
|
||||
- XML
|
||||
- XSS
|
||||
- YAML
|
||||
- ZIP
|
||||
@@ -0,0 +1,11 @@
|
||||
# adapted from Google style library
|
||||
# tests that the word following a colon is sentenced cased
|
||||
# unless it appears to be an abbreviation
|
||||
extends: existence
|
||||
message: "'%s' should be in lowercase."
|
||||
link: 'https://developers.google.com/style/colons'
|
||||
nonword: true
|
||||
level: warning
|
||||
scope: sentence
|
||||
tokens:
|
||||
- ':\s[A-Z][a-z][a-z]'
|
||||
@@ -0,0 +1,27 @@
|
||||
# adapted from Google style library
|
||||
extends: substitution
|
||||
message: "You can use '%s' instead of '%s'."
|
||||
link: 'https://developers.google.com/style/contractions'
|
||||
level: suggestion
|
||||
ignorecase: true
|
||||
action:
|
||||
name: replace
|
||||
swap:
|
||||
are not: aren't
|
||||
cannot: can't
|
||||
could not: couldn't
|
||||
did not: didn't
|
||||
do not: don't
|
||||
does not: doesn't
|
||||
has not: hasn't
|
||||
have not: haven't
|
||||
how is: how's
|
||||
is not: isn't
|
||||
should not: shouldn't
|
||||
that is: that's
|
||||
was not: wasn't
|
||||
we have: we've
|
||||
what is: what's
|
||||
when is: when's
|
||||
where is: where's
|
||||
will not: won't
|
||||
@@ -0,0 +1,10 @@
|
||||
# adapted from Google style library
|
||||
extends: existence
|
||||
message: "Use 'July 31, 2016' format, not '%s'."
|
||||
link: 'https://developers.google.com/style/dates-times'
|
||||
ignorecase: true
|
||||
level: error
|
||||
nonword: true
|
||||
tokens:
|
||||
- '\d{1,2}(?:\.|/)\d{1,2}(?:\.|/)\d{4}'
|
||||
- '\d{1,2} (?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)|May|Jun(?:e)|Jul(?:y)|Aug(?:ust)|Sep(?:tember)?|Oct(?:ober)|Nov(?:ember)?|Dec(?:ember)?) \d{4}'
|
||||
@@ -0,0 +1,10 @@
|
||||
# adapted from Google style library
|
||||
extends: existence
|
||||
message: 'In general, try not to use an ellipsis.'
|
||||
link: 'https://developers.google.com/style/ellipses'
|
||||
nonword: true
|
||||
level: warning
|
||||
action:
|
||||
name: remove
|
||||
tokens:
|
||||
- '\.\.\.'
|
||||
@@ -0,0 +1,13 @@
|
||||
# adapted from Google style library
|
||||
extends: existence
|
||||
message: "Don't put a space before or after a dash."
|
||||
link: 'https://developers.google.com/style/dashes'
|
||||
nonword: true
|
||||
level: error
|
||||
action:
|
||||
name: edit
|
||||
params:
|
||||
- remove
|
||||
- ' '
|
||||
tokens:
|
||||
- '\s[—–]\s'
|
||||
@@ -0,0 +1,14 @@
|
||||
# adapted from Google style library
|
||||
extends: existence
|
||||
message: "Use an em dash ('—') instead of '–'."
|
||||
link: 'https://developers.google.com/style/dashes'
|
||||
nonword: true
|
||||
level: error
|
||||
action:
|
||||
name: edit
|
||||
params:
|
||||
- replace
|
||||
- '-'
|
||||
- '—'
|
||||
tokens:
|
||||
- '–'
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user