Compare commits

..

8 Commits

2150 changed files with 46554 additions and 40403 deletions

View File

@ -8,15 +8,6 @@ build --noshow_progress
# Don't run manual tests
test --test_tag_filters=-manual
# Print all the options that apply to the build.
# This helps us diagnose which options override others
# (e.g. /etc/bazel.bazelrc vs. tools/bazel.rc)
build --announce_rc
# Create dist/bin symlink to $(bazel info bazel-bin)
# We use this when uploading artifacts after the build finishes
build --symlink_prefix=dist/
# Enable experimental CircleCI bazel remote cache proxy
# See remote cache documentation in /docs/BAZEL.md
build --experimental_remote_spawn_cache --remote_rest_cache=http://localhost:7643

View File

@ -12,15 +12,11 @@
## IMPORTANT
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file.
var_1: &docker_image angular/ngcontainer:0.2.0
var_2: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.2.0
# Define common ENV vars
var_3: &define_env_vars
run: echo "export PROJECT_ROOT=$(pwd)" >> $BASH_ENV
var_1: &docker_image angular/ngcontainer:0.1.0
var_2: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.1.0
# See remote cache documentation in /docs/BAZEL.md
var_4: &setup-bazel-remote-cache
var_3: &setup-bazel-remote-cache
run:
name: Start up bazel remote cache proxy
command: ~/bazel-remote-proxy -backend circleci://
@ -51,10 +47,8 @@ jobs:
- run: 'buildifier -mode=check $(find . -type f \( -name BUILD.bazel -or -name BUILD \)) ||
(echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)'
# Run the skylark linter to check our Bazel rules
# deprecated-api is disabled because we use actions.new_file(genfiles_dir)
# which has no replacement, see https://github.com/bazelbuild/bazel/issues/4858
- run: 'find . -type f -name "*.bzl" |
xargs java -jar /usr/local/bin/Skylint_deploy.jar --disable-checks=deprecated-api ||
xargs java -jar /usr/local/bin/Skylint_deploy.jar ||
(echo -e "\n.bzl files have lint errors. Please run ''yarn skylint''"; exit 1)'
- restore_cache:
@ -67,7 +61,6 @@ jobs:
<<: *job_defaults
resource_class: xlarge
steps:
- *define_env_vars
- checkout:
<<: *post_checkout
# See remote cache documentation in /docs/BAZEL.md
@ -82,29 +75,18 @@ jobs:
- run: bazel info release
- run: bazel run @yarn//:yarn
# Use bazel query so that we explicitly ask for all buildable targets to be built as well
# This avoids waiting for the slowest build target to finish before running the first test
# This avoids waiting for a build command to finish before running the first test
# See https://github.com/bazelbuild/bazel/issues/4257
# NOTE: Angular developers should typically just bazel build //packages/... or bazel test //packages/...
- run: bazel query --output=label //... | xargs bazel test
# We run the integration tests outside of Bazel for now.
# See comments inside this script.
- run: xvfb-run --auto-servernum ./integration/run_tests.sh
- run: bazel query --output=label '//modules/... union //packages/... union //tools/...' | xargs bazel test
# CircleCI will allow us to go back and view/download these artifacts from past builds.
# Also we can use a service like https://buildsize.org/ to automatically track binary size of these artifacts.
- store_artifacts:
path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js
destination: packages/core/test/bundling/hello_world/bundle.min.js
- store_artifacts:
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js
destination: packages/core/test/bundling/todo/bundle.min.js
- store_artifacts:
path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js.brotli
destination: packages/core/test/bundling/hello_world/bundle.min.js.brotli
- store_artifacts:
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.brotli
destination: packages/core/test/bundling/todo/bundle.min.js.brotli
- save_cache:
key: *cache_key
@ -112,28 +94,9 @@ jobs:
- "node_modules"
- "~/bazel_repository_cache"
aio_monitoring:
<<: *job_defaults
steps:
- checkout:
<<: *post_checkout
- restore_cache:
key: *cache_key
- run: xvfb-run --auto-servernum ./aio/scripts/test-production.sh
workflows:
version: 2
default_workflow:
jobs:
- lint
- build
aio_monitoring:
jobs:
- aio_monitoring
triggers:
- schedule:
cron: "0 0 * * *"
filters:
branches:
only:
- master

View File

@ -9,11 +9,9 @@ ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
<pre><code>
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report <!-- Please search GitHub for a similar issue or PR before submitting -->
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
[ ] Other... Please describe:
</code></pre>
## Current behavior

View File

@ -19,12 +19,10 @@ merge:
disabled: false
# the name of the status
context: "google3"
# text to show when the status is pending, {{PRNumber}} will be replaced by the PR number
pendingDesc: "Googler: run g3sync presubmit {{PRNumber}}"
# text to show when the status is pending
pendingDesc: "Googler: test this change in google3 http://go/angular-g3sync"
# text to show when the status is success
successDesc: "Does not affect google3"
# link to use for the details
url: "http://go/angular-g3sync"
# list of patterns to check for the files changed by the PR
# this list must be manually kept in sync with google3/third_party/javascript/angular2/copy.bara.sky
include:
@ -73,9 +71,9 @@ merge:
- "ci/circleci: build"
- "ci/circleci: lint"
# the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable
# {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option
# {{PLACEHOLDER}} will be replaced by the list of failing checks
# the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable
# {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option
# {{PLACEHOLDER}} will be replaced by the list of failing checks
mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label, but the following checks are still failing:
\n{{PLACEHOLDER}}
\n
@ -89,12 +87,8 @@ triage:
needsTriageMilestone: 83,
# number of the milestone to apply when the issue is triaged
defaultMilestone: 82,
# arrays of labels that determine if an issue has been triaged by the caretaker
l1TriageLabels:
-
- "comp: *"
# arrays of labels that determine if an issue has been fully triaged
l2TriageLabels:
# arrays of labels that determine if an issue is triaged
triagedLabels:
-
- "type: bug/fix"
- "severity*"

1
.gitignore vendored
View File

@ -14,7 +14,6 @@ pubspec.lock
.settings/
*.swo
modules/.settings
.bazelrc
.vscode
modules/.vscode

View File

@ -7,7 +7,6 @@
#
# alexeagle - Alex Eagle
# alxhub - Alex Rickabaugh
# andrewseguin - Andrew Seguin
# brocco - Mike Brocchi
# chuckjaz - Chuck Jazdzewski
# filipesilva - Filipe Silva
@ -303,17 +302,6 @@ groups:
- IgorMinar #fallback
- mhevery #fallback
elements:
conditions:
files:
- "packages/elements/*"
users:
- andrewseguin #primary
- gkalpak
- robwormald
- IgorMinar #fallback
- mhevery #fallback
benchpress:
conditions:
files:
@ -366,5 +354,4 @@ groups:
- petebacondarwin
- gkalpak
- IgorMinar
- robwormald
- mhevery #fallback

View File

@ -45,6 +45,7 @@ env:
matrix:
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
- CI_MODE=e2e
- CI_MODE=e2e_2
- CI_MODE=js
- CI_MODE=saucelabs_required
# deactivated, see #19768

View File

@ -1,7 +1,5 @@
package(default_visibility = ["//visibility:public"])
load("@build_bazel_rules_nodejs//:defs.bzl", "node_modules_filegroup")
exports_files([
"tsconfig.json",
"LICENSE",
@ -14,26 +12,40 @@ alias(
actual = "@yarn//:yarn",
)
node_modules_filegroup(
# This rule belongs in node_modules/BUILD
# It's here as a workaround for
# https://github.com/bazelbuild/bazel/issues/374#issuecomment-296217940
filegroup(
name = "node_modules",
packages = [
"bytebuffer",
"hammerjs",
# Performance workaround: list individual files
# Reduces the number of files as inputs to nodejs_binary:
# bazel query "deps(:node_modules)" | wc -l
# This won't scale in the general case.
# TODO(alexeagle): figure out what to do
srcs = glob(["/".join([
"node_modules",
pkg,
"**",
ext,
]) for pkg in [
"jasmine",
"minimist",
"protobufjs",
"reflect-metadata",
"source-map-support",
"tsickle",
"tslib",
"tsutils",
"typescript",
"zone.js",
"@angular-devkit/core",
"@angular-devkit/schematics",
"tsutils",
"@types",
"@webcomponents/custom-elements",
],
"tsickle",
"hammerjs",
"protobufjs",
"bytebuffer",
"reflect-metadata",
"source-map-support",
"minimist",
"tslib",
] for ext in [
"*.js",
"*.json",
"*.d.ts",
]]),
)
filegroup(
@ -42,8 +54,12 @@ filegroup(
srcs = [
"//:node_modules/reflect-metadata/Reflect.js",
"//:node_modules/zone.js/dist/zone.js",
"//:node_modules/zone.js/dist/zone-testing.js",
"//:node_modules/zone.js/dist/async-test.js",
"//:node_modules/zone.js/dist/sync-test.js",
"//:node_modules/zone.js/dist/fake-async-test.js",
"//:node_modules/zone.js/dist/task-tracking.js",
"//:node_modules/zone.js/dist/proxy.js",
"//:node_modules/zone.js/dist/jasmine-patch.js",
],
)

View File

@ -1,239 +1,3 @@
<a name="6.0.0-rc.5"></a>
# [6.0.0-rc.5](https://github.com/angular/angular/compare/6.0.0-rc.4...6.0.0-rc.5) (2018-04-14)
### Bug Fixes
* **compiler:** use correct global name in compiler.umd.js ([#23354](https://github.com/angular/angular/issues/23354)) ([b76dd3b](https://github.com/angular/angular/commit/b76dd3b)), closes [#23343](https://github.com/angular/angular/issues/23343)
* **compiler-cli:** shorten resolved module name in fileNameToModuleName to npm package name for typings ([#23231](https://github.com/angular/angular/issues/23231)) ([6199ea5](https://github.com/angular/angular/commit/6199ea5))
* **elements:** include schematics in npm distro ([#23350](https://github.com/angular/angular/issues/23350)) ([9fabe2f](https://github.com/angular/angular/commit/9fabe2f))
* **service-worker:** let `*` match 0 characters in globs ([#23339](https://github.com/angular/angular/issues/23339)) ([6c2c958](https://github.com/angular/angular/commit/6c2c958))
### Features
* **platform-browser:** add token marking which the type of animation module nearest in the injector tree ([#23075](https://github.com/angular/angular/issues/23075)) ([b551f84](https://github.com/angular/angular/commit/b551f84))
* **service-worker:** add support for configuring navigations URLs ([#23339](https://github.com/angular/angular/issues/23339)) ([08325aa](https://github.com/angular/angular/commit/08325aa)), closes [#20404](https://github.com/angular/angular/issues/20404)
<a name="6.0.0-rc.4"></a>
# [6.0.0-rc.4](https://github.com/angular/angular/compare/6.0.0-rc.3...6.0.0-rc.4) (2018-04-12)
### Bug Fixes
* **bazel:** set rollup output.name and amd.id ([#23274](https://github.com/angular/angular/issues/23274)) ([3e8eef6](https://github.com/angular/angular/commit/3e8eef6)), closes [#23238](https://github.com/angular/angular/issues/23238)
* **common:** replace i18n locale undefined values by a const ([#23265](https://github.com/angular/angular/issues/23265)) ([5706810](https://github.com/angular/angular/commit/5706810)), closes [#22988](https://github.com/angular/angular/issues/22988)
* **common:** workaround UMD/webpack limitation ([#23271](https://github.com/angular/angular/issues/23271)) ([5a298b1](https://github.com/angular/angular/commit/5a298b1)), closes [#23217](https://github.com/angular/angular/issues/23217)
* **compiler:** Pretty print object instead of [Object object] ([#22689](https://github.com/angular/angular/issues/22689)) ([8555a3a](https://github.com/angular/angular/commit/8555a3a))
* **compiler-cli:** strictMetadataEmit should not break on non-compliant libraries ([#23275](https://github.com/angular/angular/issues/23275)) ([5814355](https://github.com/angular/angular/commit/5814355)), closes [#22210](https://github.com/angular/angular/issues/22210)
* **elements:** avoid exception when window is undefined ([#23324](https://github.com/angular/angular/issues/23324)) ([af46d09](https://github.com/angular/angular/commit/af46d09))
* **platform-server:** require node v8+ ([#23331](https://github.com/angular/angular/issues/23331)) ([bbfa1d3](https://github.com/angular/angular/commit/bbfa1d3))
### Features
* **elements:** add schematics ([#23298](https://github.com/angular/angular/issues/23298)) ([37d2cb4](https://github.com/angular/angular/commit/37d2cb4))
<a name="6.0.0-rc.3"></a>
# [6.0.0-rc.3](https://github.com/angular/angular/compare/6.0.0-rc.2...6.0.0-rc.3) (2018-04-06)
### Bug Fixes
* **bazel:** don't produce ngfactory files for ng_packages ([#23237](https://github.com/angular/angular/issues/23237)) ([da58a55](https://github.com/angular/angular/commit/da58a55))
* **compiler-cli:** don't lower expressions in flat module metadata ([#23226](https://github.com/angular/angular/issues/23226)) ([11ea3a3](https://github.com/angular/angular/commit/11ea3a3))
<a name="6.0.0-rc.2"></a>
# [6.0.0-rc.2](https://github.com/angular/angular/compare/6.0.0-rc.1...6.0.0-rc.2) (2018-04-05)
### Bug Fixes
* **common:** `locales` are not being shipped ([#23136](https://github.com/angular/angular/issues/23136)) ([7ca7720](https://github.com/angular/angular/commit/7ca7720))
* **common:** properly take className changes into account ([#21937](https://github.com/angular/angular/issues/21937)) ([4a42669](https://github.com/angular/angular/commit/4a42669)), closes [#21932](https://github.com/angular/angular/issues/21932)
* **compiler-cli:** flat module index metadata should be transformed ([#23129](https://github.com/angular/angular/issues/23129)) ([f99cb5c](https://github.com/angular/angular/commit/f99cb5c))
* **core:** inject() should always work in an NgModule injection scope ([#23148](https://github.com/angular/angular/issues/23148)) ([fab6b39](https://github.com/angular/angular/commit/fab6b39)), closes [angular/material2#10586](https://github.com/angular/material2/issues/10586)
* **forms:** improve error message for invalid value accessors ([#22731](https://github.com/angular/angular/issues/22731)) ([23cc3ef](https://github.com/angular/angular/commit/23cc3ef))
* **upgrade:** correctly handle downgraded `OnPush` components ([#22209](https://github.com/angular/angular/issues/22209)) ([ad9ce5c](https://github.com/angular/angular/commit/ad9ce5c)), closes [#14286](https://github.com/angular/angular/issues/14286)
* **upgrade:** propagate return value of resumeBootstrap ([#22754](https://github.com/angular/angular/issues/22754)) ([a2330ff](https://github.com/angular/angular/commit/a2330ff)), closes [#22723](https://github.com/angular/angular/issues/22723)
### Features
* **compiler-cli:** lower loadChildren fields to allow dynamic module paths ([#23088](https://github.com/angular/angular/issues/23088)) ([550433a](https://github.com/angular/angular/commit/550433a))
<a name="6.0.0-rc.1"></a>
# [6.0.0-rc.1](https://github.com/angular/angular/compare/6.0.0-rc.0...6.0.0-rc.1) (2018-03-30)
### Bug Fixes
* **animations:** avoid animation insertions during router back/refresh ([#21977](https://github.com/angular/angular/issues/21977)) ([f88fba0](https://github.com/angular/angular/commit/f88fba0)), closes [#19712](https://github.com/angular/angular/issues/19712)
* **animations:** treat numeric state name values as strings ([#22923](https://github.com/angular/angular/issues/22923)) ([e5e1b0d](https://github.com/angular/angular/commit/e5e1b0d))
* **bazel:** complete the rollup globals list for all angular entrypoints ([#23080](https://github.com/angular/angular/issues/23080)) ([439030f](https://github.com/angular/angular/commit/439030f))
* **bazel:** don't inline tslib into fesms ([#23044](https://github.com/angular/angular/issues/23044)) ([0049743](https://github.com/angular/angular/commit/0049743))
* **bazel:** don't try to do flatmoduleindex under Blaze ([#23083](https://github.com/angular/angular/issues/23083)) ([be10bf5](https://github.com/angular/angular/commit/be10bf5))
* **bazel:** downlevel decorators in fesm5 files ([#23078](https://github.com/angular/angular/issues/23078)) ([481b22e](https://github.com/angular/angular/commit/481b22e))
* **bazel:** ng_package packages attr not forwarded to npm_package ([#22967](https://github.com/angular/angular/issues/22967)) ([2aabbc5](https://github.com/angular/angular/commit/2aabbc5))
* **bazel:** ng_package should include private exports in fesms ([#23054](https://github.com/angular/angular/issues/23054)) ([0d9140c](https://github.com/angular/angular/commit/0d9140c))
* **bazel:** pass --global option to rollup ([#23073](https://github.com/angular/angular/issues/23073)) ([45e090b](https://github.com/angular/angular/commit/45e090b))
* **common:** titlecase pipe ([#22600](https://github.com/angular/angular/issues/22600)) ([7966744](https://github.com/angular/angular/commit/7966744))
* **compiler:** don't typecheck all inputs ([#22899](https://github.com/angular/angular/issues/22899)) ([838a610](https://github.com/angular/angular/commit/838a610))
* consistently rewrite Injector to INJECTOR ([#23008](https://github.com/angular/angular/issues/23008)) ([884bf0e](https://github.com/angular/angular/commit/884bf0e))
* **compiler:** fix support for html-like text in translatable attributes ([#23053](https://github.com/angular/angular/issues/23053)) ([28058b7](https://github.com/angular/angular/commit/28058b7))
* **compiler:** take quoting into account when determining if object literals can be shared ([#22942](https://github.com/angular/angular/issues/22942)) ([d98e9e7](https://github.com/angular/angular/commit/d98e9e7))
* **compiler-cli:** use numeric comparison for TypeScript version ([#22705](https://github.com/angular/angular/issues/22705)) ([193737a](https://github.com/angular/angular/commit/193737a)), closes [#22593](https://github.com/angular/angular/issues/22593)
* **core:** don't override ngInjectableDef in the decorator if present on the type ([#22943](https://github.com/angular/angular/issues/22943)) ([6f01917](https://github.com/angular/angular/commit/6f01917))
* **service-worker:** do not enter degraded mode when offline ([#22883](https://github.com/angular/angular/issues/22883)) ([9e9b8dd](https://github.com/angular/angular/commit/9e9b8dd)), closes [#21636](https://github.com/angular/angular/issues/21636)
* **service-worker:** fix LruList bugs ([#22769](https://github.com/angular/angular/issues/22769)) ([8c2a578](https://github.com/angular/angular/commit/8c2a578)), closes [#22218](https://github.com/angular/angular/issues/22218) [#22768](https://github.com/angular/angular/issues/22768)
* **service-worker:** ignore invalid `only-if-cached` requests ([#22883](https://github.com/angular/angular/issues/22883)) ([d9dc46e](https://github.com/angular/angular/commit/d9dc46e)), closes [#22362](https://github.com/angular/angular/issues/22362)
### Features
* **bazel:** prefix private-export (barred-latin-o) symbols ([#23007](https://github.com/angular/angular/issues/23007)) ([27e14b2](https://github.com/angular/angular/commit/27e14b2))
* **compiler:** lower @NgModule ids if needed ([#23031](https://github.com/angular/angular/issues/23031)) ([bd024c0](https://github.com/angular/angular/commit/bd024c0))
<a name="6.0.0-rc.0"></a>
# [6.0.0-rc.0](https://github.com/angular/angular/compare/6.0.0-beta.8...6.0.0-rc.0) (2018-03-21)
v6 framework is now feature complete, the cli and material/cdk parts of the v6 release and other integrations are still
in works and will be completed by the time we cut v6.0.0.
Please [file new issues](https://github.com/angular/angular/issues/new) at our issue tracker with as many details as
possible, and ideally also a include a good reproduction of the problem.
### Bug Fixes
* **bazel:** correct expected outs for external sources in ng_module ([#22755](https://github.com/angular/angular/issues/22755)) ([bfe077a](https://github.com/angular/angular/commit/bfe077a))
* **compiler:** do not emit line/char in ngsummary files. ([#22840](https://github.com/angular/angular/issues/22840)) ([5c387a7](https://github.com/angular/angular/commit/5c387a7))
* correct several esm2015 entry-points in package.jsons ([#22892](https://github.com/angular/angular/issues/22892)) ([7d095b9](https://github.com/angular/angular/commit/7d095b9))
* **router:** don't use spread operator to workaround an issue in closure compiler ([#22884](https://github.com/angular/angular/issues/22884)) ([e6c731f](https://github.com/angular/angular/commit/e6c731f))
* **router:** make locationSyncBootstrapListener public due to change in output after TS 2.7 update in [#22669](https://github.com/angular/angular/issues/22669) ([#22896](https://github.com/angular/angular/issues/22896)) ([623d769](https://github.com/angular/angular/commit/623d769))
* **upgrade:** two-way binding and listening for event ([#22772](https://github.com/angular/angular/issues/22772)) ([2b3de63](https://github.com/angular/angular/commit/2b3de63)), closes [#22734](https://github.com/angular/angular/issues/22734)
### Features
* **core:** update the package output of build.sh to [APF v6](https://goo.gl/jB3GVv) ([#22808](https://github.com/angular/angular/issues/22808)) ([ce63dc6](https://github.com/angular/angular/commit/ce63dc6))
* **core:** upgrade rxjs to 6.0.0-beta.0, please see this [RxJS Upgrade Guide](https://goo.gl/osWFzo) for more info ([#22573](https://github.com/angular/angular/issues/22573)) ([b43f8bc](https://github.com/angular/angular/commit/b43f8bc))
<a name="6.0.0-beta.8"></a>
# [6.0.0-beta.8](https://github.com/angular/angular/compare/6.0.0-beta.7...6.0.0-beta.8) (2018-03-16)
### Bug Fixes
* **aio:** constrain error logging to improve reporting ([#22713](https://github.com/angular/angular/issues/22713)) ([049757b](https://github.com/angular/angular/commit/049757b))
* **compiler-cli:** annotate Ivy fields as [@nocollapse](https://github.com/nocollapse) in closure mode ([#22691](https://github.com/angular/angular/issues/22691)) ([6e00410](https://github.com/angular/angular/commit/6e00410))
* **compiler-cli:** disableTypeScriptVersionCheck should be applied even for older tsc versions ([#22669](https://github.com/angular/angular/issues/22669)) ([3f70aba](https://github.com/angular/angular/commit/3f70aba))
* **compiler-cli:** emit correct css string escape sequences ([#22776](https://github.com/angular/angular/issues/22776)) ([6e5e819](https://github.com/angular/angular/commit/6e5e819))
* **compiler-cli:** enableResourceInlining handles both styles and styleUrls ([#22688](https://github.com/angular/angular/issues/22688)) ([40315be](https://github.com/angular/angular/commit/40315be))
* **compiler-cli:** generate proper exports.* identifiers in cjs output ([#22564](https://github.com/angular/angular/issues/22564)) ([0d8deb0](https://github.com/angular/angular/commit/0d8deb0))
* **compiler-cli:** resolve resource URLs before loading them under enableResourceInlining ([#22688](https://github.com/angular/angular/issues/22688)) ([123efba](https://github.com/angular/angular/commit/123efba))
* **core:** remove core animation import symbols ([#22692](https://github.com/angular/angular/issues/22692)) ([f5a98f4](https://github.com/angular/angular/commit/f5a98f4))
* **elements:** fix elements test bootstrap ([#22839](https://github.com/angular/angular/issues/22839)) ([5d82d8d](https://github.com/angular/angular/commit/5d82d8d))
* overloading a function doesn't generate all of the signatures ([#22569](https://github.com/angular/angular/issues/22569)) ([e8326e6](https://github.com/angular/angular/commit/e8326e6))
* **platform-server:** add styles to elements correctly ([#22527](https://github.com/angular/angular/issues/22527)) ([cd2ebd2](https://github.com/angular/angular/commit/cd2ebd2))
* **router:** correct over-encoding of URL fragment ([#22687](https://github.com/angular/angular/issues/22687)) ([0bf6fa5](https://github.com/angular/angular/commit/0bf6fa5))
### Code Refactoring
* **compiler:** Drop support for the deprecated `<template>`. Use `<ng-template>` instead ([#22783](https://github.com/angular/angular/issues/22783)) ([0ebd577](https://github.com/angular/angular/commit/0ebd577))
### Features
* **aio:** add hack, remove me ([#22413](https://github.com/angular/angular/issues/22413)) ([4d506ac](https://github.com/angular/angular/commit/4d506ac))
* **aio:** migrate embedded comp to elements ([#22413](https://github.com/angular/angular/issues/22413)) ([7c9b411](https://github.com/angular/angular/commit/7c9b411))
* **aio:** update payload size ([#22413](https://github.com/angular/angular/issues/22413)) ([400460c](https://github.com/angular/angular/commit/400460c))
* **animations:** expose `element` and `params` within transition matchers ([#22693](https://github.com/angular/angular/issues/22693)) ([58b94e6](https://github.com/angular/angular/commit/58b94e6))
* **bazel:** change ng_package rule to APF v6 ([#22782](https://github.com/angular/angular/issues/22782)) ([88b3198](https://github.com/angular/angular/commit/88b3198))
* **compiler:** support for singleline, multiline & jsdoc comments ([#22715](https://github.com/angular/angular/issues/22715)) ([3b167be](https://github.com/angular/angular/commit/3b167be))
* **compiler-cli:** add resource inlining to ngc ([#22615](https://github.com/angular/angular/issues/22615)) ([b5be18f](https://github.com/angular/angular/commit/b5be18f))
* **compiler-cli:** require node 8 as runtime engine ([#22669](https://github.com/angular/angular/issues/22669)) ([c602563](https://github.com/angular/angular/commit/c602563))
* **core:** add task tracking to Testability ([#16863](https://github.com/angular/angular/issues/16863)) ([37fedd0](https://github.com/angular/angular/commit/37fedd0))
* **elements:** add polyfill for elements es5 shim ([#22413](https://github.com/angular/angular/issues/22413)) ([863aff1](https://github.com/angular/angular/commit/863aff1))
* **elements:** add support for creating custom elements ([#22413](https://github.com/angular/angular/issues/22413)) ([22b96b9](https://github.com/angular/angular/commit/22b96b9))
* **elements:** add tests for component factory strategy ([#22413](https://github.com/angular/angular/issues/22413)) ([d2be675](https://github.com/angular/angular/commit/d2be675))
* **elements:** another polyfill solution ([#22413](https://github.com/angular/angular/issues/22413)) ([cf3ff7d](https://github.com/angular/angular/commit/cf3ff7d))
* **elements:** fix lint ([#22413](https://github.com/angular/angular/issues/22413)) ([0b45dfa](https://github.com/angular/angular/commit/0b45dfa))
* **elements:** fix payload size ([#22413](https://github.com/angular/angular/issues/22413)) ([fe21437](https://github.com/angular/angular/commit/fe21437))
* **elements:** fix test ([#22413](https://github.com/angular/angular/issues/22413)) ([44f637a](https://github.com/angular/angular/commit/44f637a))
* **elements:** George's comments ([#22413](https://github.com/angular/angular/issues/22413)) ([46efd4b](https://github.com/angular/angular/commit/46efd4b))
* **elements:** injector create ([#22413](https://github.com/angular/angular/issues/22413)) ([87f60bc](https://github.com/angular/angular/commit/87f60bc))
* **elements:** make bazel happy ([#22413](https://github.com/angular/angular/issues/22413)) ([39a12d2](https://github.com/angular/angular/commit/39a12d2))
* **elements:** provide type, not factory; remove config need ([#22413](https://github.com/angular/angular/issues/22413)) ([1936808](https://github.com/angular/angular/commit/1936808))
* **elements:** rebase ([#22413](https://github.com/angular/angular/issues/22413)) ([d72f445](https://github.com/angular/angular/commit/d72f445))
* **elements:** remove attribute/input from config ([#22413](https://github.com/angular/angular/issues/22413)) ([688096b](https://github.com/angular/angular/commit/688096b))
* **elements:** rename API to createCustomElement ([#22413](https://github.com/angular/angular/issues/22413)) ([167fdf7](https://github.com/angular/angular/commit/167fdf7))
* **elements:** update package.json with latest ([#22413](https://github.com/angular/angular/issues/22413)) ([2e450f6](https://github.com/angular/angular/commit/2e450f6))
* mark angular packages as side-effect free ([#22785](https://github.com/angular/angular/issues/22785)) ([44de10e](https://github.com/angular/angular/commit/44de10e))
* tree-shakeable providers API updates ([#22655](https://github.com/angular/angular/issues/22655)) ([db56836](https://github.com/angular/angular/commit/db56836))
* update tslib to 1.9.0 ([#22667](https://github.com/angular/angular/issues/22667)) ([489fec1](https://github.com/angular/angular/commit/489fec1))
### BREAKING CHANGES
* **compiler:** The `<template>` tag was deprecated in Angular v4 to avoid collisions (i.e. when
using Web Components).
This commit removes support for `<template>`. `<ng-template>` should be used
instead.
BEFORE:
<!-- html template -->
<template>some template content</template>
# tsconfig.json
{
# ...
"angularCompilerOptions": {
# ...
# This option is no more supported and will have no effect
"enableLegacyTemplate": [true|false]
}
}
AFTER:
<!-- html template -->
<ng-template>some template content</ng-template>
* **core:** it is no longer possible to import
animation-related functions from @angular/core. All
animation symbols must now be imported from @angular/animations.
* after this change, npm and yarn will issue incompatible peerDependencies warning
We don't expect this to actually break an application, but the application/library package.json
will need to be updated to provide tslib 1.9.0 or higher.
<a name="5.2.9"></a>
## [5.2.9](https://github.com/angular/angular/compare/5.2.8...5.2.9) (2018-03-14)
### Bug Fixes
* **platform-server:** add styles to elements correctly ([#22527](https://github.com/angular/angular/issues/22527)) ([fc6dfc2](https://github.com/angular/angular/commit/fc6dfc2))
* **router:** correct over-encoding of URL fragment ([#22687](https://github.com/angular/angular/issues/22687)) ([86517f2](https://github.com/angular/angular/commit/86517f2))
<a name="6.0.0-beta.7"></a>
# [6.0.0-beta.7](https://github.com/angular/angular/compare/6.0.0-beta.6...6.0.0-beta.7) (2018-03-07)
@ -462,7 +226,7 @@ If that is the case, you should be able to track the old value directly by savin
* **common:** don't convert null to a string when flushing a mock request ([#21417](https://github.com/angular/angular/issues/21417)) ([8b14488](https://github.com/angular/angular/commit/8b14488)), closes [#20744](https://github.com/angular/angular/issues/20744)
* **core:** fix [#20582](https://github.com/angular/angular/issues/20582), don't need to wrap zone in location change listener ([#20640](https://github.com/angular/angular/issues/20640)) ([f791e9f](https://github.com/angular/angular/commit/f791e9f))
* **core:** fix proper propagation of subscriptions in EventEmitter ([#22016](https://github.com/angular/angular/issues/22016)) ([e81606c](https://github.com/angular/angular/commit/e81606c)), closes [#21999](https://github.com/angular/angular/issues/21999)
* **core:** should check Zone existence when scheduleMicroTask ([#20656](https://github.com/angular/angular/issues/20656)) ([3a86940](https://github.com/angular/angular/commit/3a86940))
* **core:** should check Zone existance when scheduleMicroTask ([#20656](https://github.com/angular/angular/issues/20656)) ([3a86940](https://github.com/angular/angular/commit/3a86940))
* **forms:** publish missing types ([#19941](https://github.com/angular/angular/issues/19941)) ([2707012](https://github.com/angular/angular/commit/2707012))
* **ivy:** generate correct interpolations ([#21946](https://github.com/angular/angular/issues/21946)) ([3cc1d76](https://github.com/angular/angular/commit/3cc1d76))
* **ivy:** generate lifecycle pattern ([#21865](https://github.com/angular/angular/issues/21865)) ([f816666](https://github.com/angular/angular/commit/f816666))
@ -493,7 +257,7 @@ If that is the case, you should be able to track the old value directly by savin
* **common:** don't convert null to a string when flushing a mock request ([#21417](https://github.com/angular/angular/issues/21417)) ([c4fb696](https://github.com/angular/angular/commit/c4fb696)), closes [#20744](https://github.com/angular/angular/issues/20744)
* **core:** fix [#20582](https://github.com/angular/angular/issues/20582), don't need to wrap zone in location change listener ([#22007](https://github.com/angular/angular/issues/22007)) ([ce51ea9](https://github.com/angular/angular/commit/ce51ea9))
* **core:** fix proper propagation of subscriptions in EventEmitter ([#22016](https://github.com/angular/angular/issues/22016)) ([c6645e7](https://github.com/angular/angular/commit/c6645e7)), closes [#21999](https://github.com/angular/angular/issues/21999)
* **core:** should check Zone existence when scheduleMicroTask ([#20656](https://github.com/angular/angular/issues/20656)) ([aa9ba7f](https://github.com/angular/angular/commit/aa9ba7f))
* **core:** should check Zone existance when scheduleMicroTask ([#20656](https://github.com/angular/angular/issues/20656)) ([aa9ba7f](https://github.com/angular/angular/commit/aa9ba7f))
@ -1914,7 +1678,7 @@ From 4.0.0 @angular/core uses a [`WeakMap`](https://github.com/angular/angular/c
* **compiler:** make sourcemaps work in AOT mode ([492153a](https://github.com/angular/angular/commit/492153a))
* **compiler:** only warn for `[@Injectable](https://github.com/Injectable)` classes with invalid args. ([5c34066](https://github.com/angular/angular/commit/5c34066)), closes [#15003](https://github.com/angular/angular/issues/15003)
* **compiler:** shouldn't throw when Symbol is used as DI token ([#13701](https://github.com/angular/angular/issues/13701)) ([8b5c6b2](https://github.com/angular/angular/commit/8b5c6b2)), closes [#13314](https://github.com/angular/angular/issues/13314)
* **compiler:** support interface types in injectable constructors ([#14894](https://github.com/angular/angular/issues/14894)) ([b00fe20](https://github.com/angular/angular/commit/b00fe20)), closes [#12631](https://github.com/angular/angular/issues/12631)
* **compiler:** support interface types in injectable constuctors ([#14894](https://github.com/angular/angular/issues/14894)) ([b00fe20](https://github.com/angular/angular/commit/b00fe20)), closes [#12631](https://github.com/angular/angular/issues/12631)
* **compiler:** warning prints "WARNING" instead of "ERROR" ([#15125](https://github.com/angular/angular/issues/15125)) ([3b1956b](https://github.com/angular/angular/commit/3b1956b))
* **core:** dont recreate `TemplateRef` when used as a reference. ([#15066](https://github.com/angular/angular/issues/15066)) ([df914ef](https://github.com/angular/angular/commit/df914ef)), closes [#14873](https://github.com/angular/angular/issues/14873)
* **core:** dont throw if queries change during change detection. ([06fc42b](https://github.com/angular/angular/commit/06fc42b)), closes [#14925](https://github.com/angular/angular/issues/14925)
@ -1954,7 +1718,7 @@ From 4.0.0 @angular/core uses a [`WeakMap`](https://github.com/angular/angular/c
### BREAKING CHANGES
* Previously, any provider that had an ngOnDestroy lifecycle hook would be created eagerly.
* Perviously, any provider that had an ngOnDestroy lifecycle hook would be created eagerly.
Now, only classes that are annotated with @Component, @Directive, @Pipe, @NgModule are eager. Providers only become eager if they are either directly or transitively injected into one of the above.
@ -2222,7 +1986,7 @@ Note: the 4.0.0-rc.0 release on npm accidentally omitted one bug fix, so we cut
* **compiler:** improve error message for unknown elements ([#14373](https://github.com/angular/angular/issues/14373)) ([2c6dab9](https://github.com/angular/angular/commit/2c6dab9))
* **compiler:** improve error messages in aot compiler ([#14333](https://github.com/angular/angular/issues/14333)) ([a696f4a](https://github.com/angular/angular/commit/a696f4a))
* **compiler:** improve error msg for unknown properties on ([#14373](https://github.com/angular/angular/issues/14373)) ([e5a144d](https://github.com/angular/angular/commit/e5a144d)), closes [#14070](https://github.com/angular/angular/issues/14070)
* **core:** Remove ChangeDetectorRef Parameter from KeyValueDifferFactory and IterableDifferFactory ([#14311](https://github.com/angular/angular/issues/14311)) ([45cc444](https://github.com/angular/angular/commit/45cc444))
* **core:** Remove ChangeDetectorRef Paramter from KeyValueDifferFactory and IterableDifferFactory ([#14311](https://github.com/angular/angular/issues/14311)) ([45cc444](https://github.com/angular/angular/commit/45cc444))
* **core:** suppress a Closure Compiler warning ([#14484](https://github.com/angular/angular/issues/14484)) ([2f2b65b](https://github.com/angular/angular/commit/2f2b65b))
* **forms:** getRawValue should correctly work with nested FormGroups/Arrays ([#12964](https://github.com/angular/angular/issues/12964)) ([1ece736](https://github.com/angular/angular/commit/1ece736)), closes [#12963](https://github.com/angular/angular/issues/12963)
* **http:** REVERT: remove dots from jsonp callback name ([#13219](https://github.com/angular/angular/issues/13219)) ([4676df5](https://github.com/angular/angular/commit/4676df5))
@ -2407,7 +2171,7 @@ returned value being an array.
### Bug Fixes
* **common:** add PopStateEvent interface ([#13400](https://github.com/angular/angular/issues/13400)) ([71567d1](https://github.com/angular/angular/commit/71567d1)), closes [#13378](https://github.com/angular/angular/issues/13378)
* **common:** DatePipe doesn't throw for NaN ([#14117](https://github.com/angular/angular/issues/14117)) ([32cc675](https://github.com/angular/angular/commit/32cc675)), closes [#14103](https://github.com/angular/angular/issues/14103)
* **common:** DatePipe does't throw for NaN ([#14117](https://github.com/angular/angular/issues/14117)) ([32cc675](https://github.com/angular/angular/commit/32cc675)), closes [#14103](https://github.com/angular/angular/issues/14103)
* **common:** DatePipe parses input string if it's not a valid date in browser ([#13895](https://github.com/angular/angular/issues/13895)) ([e641636](https://github.com/angular/angular/commit/e641636)), closes [#12334](https://github.com/angular/angular/issues/12334) [#13874](https://github.com/angular/angular/issues/13874)
* **common:** introduce isObservable method ([#14067](https://github.com/angular/angular/issues/14067)) ([109f0d1](https://github.com/angular/angular/commit/109f0d1)), closes [#8848](https://github.com/angular/angular/issues/8848)
* **compiler:** allow empty translations for attributes ([#14085](https://github.com/angular/angular/issues/14085)) ([f3d5506](https://github.com/angular/angular/commit/f3d5506)), closes [#13897](https://github.com/angular/angular/issues/13897)
@ -2825,7 +2589,7 @@ We are adding more tests to our test suite to catch these kinds of problems befo
* **common:** make sure the plural category exists ([#13169](https://github.com/angular/angular/issues/13169)) ([82c81cd](https://github.com/angular/angular/commit/82c81cd)), closes [#12379](https://github.com/angular/angular/issues/12379)
* **compiler:** include the summaries of reexported modules / directives / pipes ([#13196](https://github.com/angular/angular/issues/13196)) ([75d1617](https://github.com/angular/angular/commit/75d1617))
* **compiler:** serialize any `StaticSymbol` correctly, not matter in which context ([5614c4f](https://github.com/angular/angular/commit/5614c4f))
* **compiler:** short-circuit expressions with an index ([#13263](https://github.com/angular/angular/issues/13263)) ([f31c947](https://github.com/angular/angular/commit/f31c947)), closes [#13254](https://github.com/angular/angular/issues/13254)
* **compiler:** short-circut expressions with an index ([#13263](https://github.com/angular/angular/issues/13263)) ([f31c947](https://github.com/angular/angular/commit/f31c947)), closes [#13254](https://github.com/angular/angular/issues/13254)
* **core:** display framework version on bootstrapped component ([#13252](https://github.com/angular/angular/issues/13252)) ([16efb13](https://github.com/angular/angular/commit/16efb13))
* **facade:** cache original format string ([#12764](https://github.com/angular/angular/issues/12764)) ([a132287](https://github.com/angular/angular/commit/a132287))
* **http:** set the default Accept header ([#12989](https://github.com/angular/angular/issues/12989)) ([986abbe](https://github.com/angular/angular/commit/986abbe)), closes [#6354](https://github.com/angular/angular/issues/6354)

View File

@ -212,7 +212,6 @@ The following is the list of supported scopes:
* **compiler**
* **compiler-cli**
* **core**
* **elements**
* **forms**
* **http**
* **language-service**

View File

@ -2,27 +2,24 @@ workspace(name = "angular")
http_archive(
name = "build_bazel_rules_nodejs",
url = "https://github.com/bazelbuild/rules_nodejs/archive/1931156c232a08356dfda02e9c8b0275c2e63c00.zip",
strip_prefix = "rules_nodejs-1931156c232a08356dfda02e9c8b0275c2e63c00",
sha256 = "9cfe33276a6ac0076ee9ee159c4a2576f9851c0f437435b5ac19b2e592493078",
url = "https://github.com/bazelbuild/rules_nodejs/archive/f03c8b5df155da2a640b6775afdd4fe4aa6fec72.zip",
strip_prefix = "rules_nodejs-f03c8b5df155da2a640b6775afdd4fe4aa6fec72",
sha256 = "9d541f49af8cf60c73efb102186bfa5670ee190a088ce52638dcdf90cd9e2de6",
)
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install")
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories")
check_bazel_version("0.11.1")
node_repositories(package_json = ["//:package.json"])
yarn_install(
name = "ts-api-guardian_runtime_deps",
package_json = "//tools/ts-api-guardian:package.json",
yarn_lock = "//tools/ts-api-guardian:yarn.lock",
)
check_bazel_version("0.9.0")
node_repositories(package_json = [
"//:package.json",
"//tools/ts-api-guardian:package.json",
])
http_archive(
name = "build_bazel_rules_typescript",
url = "https://github.com/bazelbuild/rules_typescript/archive/0.12.1.zip",
strip_prefix = "rules_typescript-0.12.1",
sha256 = "24e2c36f60508c6d270ae4265b89b381e3f66d550e70c367ed3755ad8d7ce3b0",
url = "https://github.com/bazelbuild/rules_typescript/archive/0.11.1.zip",
strip_prefix = "rules_typescript-0.11.1",
sha256 = "7406bea7954e1c906f075115dfa176551a881119f6820b126ea1eacb09f34a1a",
)
load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace")
@ -34,29 +31,22 @@ local_repository(
path = "node_modules/rxjs/src",
)
# Point to the integration test workspace just so that Bazel doesn't descend into it
# when expanding the //... pattern
local_repository(
name = "bazel_integration_test",
path = "integration/bazel",
)
# This commit matches the version of buildifier in angular/ngcontainer
# If you change this, also check if it matches the version in the angular/ngcontainer
# version in /.circleci/config.yml
BAZEL_BUILDTOOLS_VERSION = "70bc7843bb9950fece2bc014ed16de03419e36e2"
BAZEL_BUILDTOOLS_VERSION = "b3b620e8bcff18ed3378cd3f35ebeb7016d71f71"
http_archive(
name = "com_github_bazelbuild_buildtools",
url = "https://github.com/bazelbuild/buildtools/archive/%s.zip" % BAZEL_BUILDTOOLS_VERSION,
strip_prefix = "buildtools-%s" % BAZEL_BUILDTOOLS_VERSION,
sha256 = "367c23a5fe7fc2a7cb57863d3718b4149f0e57426c48c8ad54c45348a0b53cc1",
sha256 = "dad19224258ed67cbdbae9b7befb785c3b966e5a33b04b3ce58ddb7824b97d73",
)
http_archive(
name = "io_bazel_rules_go",
url = "https://github.com/bazelbuild/rules_go/releases/download/0.10.3/rules_go-0.10.3.tar.gz",
sha256 = "feba3278c13cde8d67e341a837f69a029f698d7a27ddbb2a202be7a10b22142a",
url = "https://github.com/bazelbuild/rules_go/releases/download/0.7.1/rules_go-0.7.1.tar.gz",
sha256 = "341d5eacef704415386974bc82a1783a8b7ffbff2ab6ba02375e1ca20d9b031c",
)
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
@ -68,9 +58,9 @@ go_register_toolchains()
# Fetching the Bazel source code allows us to compile the Skylark linter
http_archive(
name = "io_bazel",
url = "https://github.com/bazelbuild/bazel/archive/5a35e72f9e97c06540c479f8c31512fb4656202f.zip",
strip_prefix = "bazel-5a35e72f9e97c06540c479f8c31512fb4656202f",
sha256 = "ed33a52874c14e3b487fb50f390c541fab9c81a33d986d38fb01766a66dbcd21",
url = "https://github.com/bazelbuild/bazel/archive/9755c72b48866ed034bd28aa033e9abd27431b1e.zip",
strip_prefix = "bazel-9755c72b48866ed034bd28aa033e9abd27431b1e",
sha256 = "5b8443fc3481b5fcd9e7f348e1dd93c1397f78b223623c39eb56494c55f41962",
)
# We have a source dependency on the Devkit repository, because it's built with
@ -88,7 +78,7 @@ http_archive(
http_archive(
name = "org_brotli",
url = "https://github.com/google/brotli/archive/c6333e1e79fb62ea088443f192293f964409b04e.zip",
strip_prefix = "brotli-c6333e1e79fb62ea088443f192293f964409b04e",
sha256 = "3f781988dee7dd3bcce2bf238294663cfaaf3b6433505bdb762e24d0a284d1dc",
url = "https://github.com/google/brotli/archive/v1.0.2.zip",
strip_prefix = "brotli-1.0.2",
sha256 = "b43d5d6bc40f2fa6c785b738d86c6bbe022732fe25196ebbe43b9653a025920d",
)

View File

@ -13,9 +13,7 @@
"app/search/search-worker.js",
"favicon.ico",
"pwa-manifest.json",
"google385281288605d160.html",
{ "glob": "custom-elements.min.js", "input": "../node_modules/@webcomponents/custom-elements", "output": "./assets/js" },
{ "glob": "native-shim.js", "input": "../node_modules/@webcomponents/custom-elements/src", "output": "./assets/js" }
"google385281288605d160.html"
],
"index": "index.html",
"main": "main.ts",
@ -68,6 +66,5 @@
"build": {
"namedChunks": true
}
},
"packageManager": "yarn"
}
}

3
aio/.gitignore vendored
View File

@ -30,7 +30,6 @@
/connect.lock
/coverage
/libpeerconnection.log
debug.log
npm-debug.log
testem.log
/typings
@ -46,4 +45,4 @@ protractor-results*.txt
Thumbs.db
# copied dependencies
src/assets/js/lunr*
src/assets/js/lunr*

View File

@ -19,8 +19,8 @@ ARG AIO_DOMAIN_NAME=ngbuilds.io
ARG TEST_AIO_DOMAIN_NAME=$AIO_DOMAIN_NAME.localhost
ARG AIO_GITHUB_ORGANIZATION=angular
ARG TEST_AIO_GITHUB_ORGANIZATION=angular
ARG AIO_GITHUB_TEAM_SLUGS=team,aio-contributors
ARG TEST_AIO_GITHUB_TEAM_SLUGS=team,aio-contributors
ARG AIO_GITHUB_TEAM_SLUGS=angular-core,aio-contributors
ARG TEST_AIO_GITHUB_TEAM_SLUGS=angular-core,aio-contributors
ARG AIO_NGINX_HOSTNAME=$AIO_DOMAIN_NAME
ARG TEST_AIO_NGINX_HOSTNAME=$TEST_AIO_DOMAIN_NAME
ARG AIO_NGINX_PORT_HTTP=80

View File

@ -9,7 +9,7 @@ Necessary secrets:
- Used for:
- Retrieving open PRs without rate-limiting.
- Retrieving PR author.
- Retrieving members of the trusted GitHub teams.
- Retrieving members of the `angular-core` team.
- Posting comments with preview links on PRs.
2. `PREVIEW_DEPLOYMENT_TOKEN`

View File

@ -74,7 +74,7 @@ sudo docker run \
## Example
The following command would start a docker container based on the previously created `foobar-builds`
docker image, alias it as 'foobar-builds-1' and map predefined directories on the host VM to be used
by the container for accessing secrets and SSL certificates and keeping the build artifacts and logs.
by the container for accesing secrets and SSL certificates and keeping the build artifacts and logs.
```
sudo docker run \

View File

@ -15,7 +15,7 @@ export class BackendService {
getAll(type: Type<any>): PromiseLike<any[]> {
if (type === Hero) {
// TODO: get from the database
// TODO get from the database
return Promise.resolve<Hero[]>(HEROES);
}
let err = new Error('Cannot get object of this type');

View File

@ -8,7 +8,7 @@ import { MinimalLogger } from './minimal-logger.service';
@Component({
selector: 'app-hero-of-the-month',
templateUrl: './hero-of-the-month.component.html',
// TODO: move this aliasing, `useExisting` provider to the AppModule
// Todo: move this aliasing, `useExisting` provider to the AppModule
providers: [{ provide: MinimalLogger, useExisting: LoggerService }]
})
export class HeroOfTheMonthComponent {

View File

@ -5,7 +5,7 @@ import { Hero } from './hero';
@Injectable()
export class HeroService {
// TODO: move to database
// TODO move to database
private heroes: Array<Hero> = [
new Hero(1, 'RubberMan', 'Hero of many talents', '123-456-7899'),
new Hero(2, 'Magma', 'Hero of all trades', '555-555-5555'),

View File

@ -151,7 +151,7 @@ export class BethComponent implements Parent {
// #docregion alex-1
})
// #enddocregion alex-1
// TODO: Add `... implements Parent` to class signature
// Todo: Add `... implements Parent` to class signature
// #docregion alex-1
// #docregion alex-class-signature
export class AlexComponent extends Base

View File

@ -178,11 +178,6 @@ describe('Dependency Injection Tests', function () {
expect(heroes.count()).toBeGreaterThan(0);
});
it('authorized user should have multiple authorized heroes with tree-shakeable HeroesService', function () {
let heroes = element.all(by.css('#tspAuthorized app-hero-list div'));
expect(heroes.count()).toBeGreaterThan(0);
});
it('authorized user should have secret heroes', function () {
let heroes = element.all(by.css('#authorized app-hero-list div'));
expect(heroes.count()).toBeGreaterThan(0);

View File

@ -21,7 +21,6 @@ import { UserService } from './user.service';
<p>
<app-heroes id="authorized" *ngIf="isAuthorized"></app-heroes>
<app-heroes id="unauthorized" *ngIf="!isAuthorized"></app-heroes>
<app-heroes-tsp id="tspAuthorized" *ngIf="isAuthorized"></app-heroes-tsp>
<app-providers></app-providers>
`
})

View File

@ -6,7 +6,6 @@ import { APP_CONFIG, HERO_DI_CONFIG } from './app.config';
import { AppComponent } from './app.component';
import { CarComponent } from './car/car.component';
import { HeroesComponent } from './heroes/heroes.component';
import { HeroesTspComponent } from './heroes/heroes-tsp.component';
import { HeroListComponent } from './heroes/hero-list.component';
import { InjectorComponent } from './injector.component';
import { Logger } from './logger.service';
@ -26,7 +25,6 @@ import { ProvidersModule } from './providers.module';
CarComponent,
HeroesComponent,
// #enddocregion ngmodule
HeroesTspComponent,
HeroListComponent,
InjectorComponent,
TestComponent

View File

@ -1,6 +0,0 @@
// #docregion
import { NgModule } from '@angular/core';
@NgModule({})
export class HeroModule {
}

View File

@ -1,8 +1,6 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
@Injectable()
export class HeroService {
constructor() { }
}

View File

@ -2,9 +2,7 @@
import { Injectable } from '@angular/core';
import { HEROES } from './mock-heroes';
@Injectable({
providedIn: 'root',
})
@Injectable()
export class HeroService {
getHeroes() { return HEROES; }
}

View File

@ -3,9 +3,7 @@ import { Injectable } from '@angular/core';
import { HEROES } from './mock-heroes';
import { Logger } from '../logger.service';
@Injectable({
providedIn: 'root',
})
@Injectable()
export class HeroService {
// #docregion ctor

View File

@ -1,13 +0,0 @@
// #docregion
import { Injectable } from '@angular/core';
import { HEROES } from './mock-heroes';
@Injectable({
// we declare that this service should be created
// by the root application injector.
providedIn: 'root',
})
export class HeroService {
getHeroes() { return HEROES; }
}

View File

@ -1,14 +0,0 @@
// #docregion
import { Injectable } from '@angular/core';
import { HeroModule } from './hero.module';
import { HEROES } from './mock-heroes';
@Injectable({
// we declare that this service should be created
// by any injector that includes HeroModule.
providedIn: HeroModule,
})
export class HeroService {
getHeroes() { return HEROES; }
}

View File

@ -2,14 +2,8 @@
import { Injectable } from '@angular/core';
import { HEROES } from './mock-heroes';
import { Logger } from '../logger.service';
import { UserService } from '../user.service';
@Injectable({
providedIn: 'root',
useFactory: (logger: Logger, userService: UserService) =>
new HeroService(logger, userService.user.isAuthorized),
deps: [Logger, UserService],
})
@Injectable()
export class HeroService {
// #docregion internals
constructor(

View File

@ -1,16 +0,0 @@
import { Component } from '@angular/core';
/**
* A version of `HeroesComponent` that does not provide the `HeroService` (and thus relies on its
* `Injectable`-declared provider) in order to function.
*
* TSP stands for Tree-Shakeable Provider.
*/
@Component({
selector: 'app-heroes-tsp',
template: `
<h2>Heroes</h2>
<app-hero-list></app-hero-list>
`
})
export class HeroesTspComponent { }

View File

@ -1,15 +0,0 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { ServiceModule } from './service-and-module';
// #docregion
@NgModule({
imports: [
BrowserModule,
RouterModule.forRoot([]),
ServiceModule,
],
})
export class AppModule {
}

View File

@ -1,14 +0,0 @@
// #docregion
import { Injectable, NgModule } from '@angular/core';
@Injectable()
export class Service {
doSomething(): void {
}
}
@NgModule({
providers: [Service],
})
export class ServiceModule {
}

View File

@ -1,11 +0,0 @@
import { Injectable } from '@angular/core';
// #docregion
@Injectable({
providedIn: 'root',
useFactory: () => new Service('dependency'),
})
export class Service {
constructor(private dep: string) {
}
}

View File

@ -1,8 +0,0 @@
import { Injectable } from '@angular/core';
// #docregion
@Injectable({
providedIn: 'root',
})
export class Service {
}

View File

@ -7,7 +7,7 @@ export class User {
public isAuthorized = false) { }
}
// TODO: get the user; don't 'new' it.
// Todo: get the user; don't 'new' it.
let alice = new User('Alice', true);
let bob = new User('Bob', false);

View File

@ -3,7 +3,7 @@
"files":[
"!**/*.d.ts",
"!**/*.js",
"!**/*.[0,1,2,3,4].*",
"!**/*.[0,1,2].*",
"!**/dummy.module.ts"
],
"tags": ["dependency", "di"]

View File

@ -8,8 +8,8 @@ import { TextboxQuestion } from './question-textbox';
@Injectable()
export class QuestionService {
// TODO: get from a remote source of question metadata
// TODO: make asynchronous
// Todo: get from a remote source of question metadata
// Todo: make asynchronous
getQuestions() {
let questions: QuestionBase<any>[] = [

View File

@ -1,26 +0,0 @@
// #docregion
import { Component, Injector } from '@angular/core';
import { createNgElementConstructor } from '../elements-dist';
import { PopupService } from './popup.service';
import { PopupComponent } from './popup.component';
@Component({
selector: 'app-root',
template: `
<input #input value="Message">
<button (click)="popup.showAsComponent(input.value)">
Show as component </button>
<button (click)="popup.showAsElement(input.value)">
Show as element </button>
`
})
export class AppComponent {
constructor(private injector: Injector, public popup: PopupService) {
// on init, convert PopupComponent to a custom element
const PopupElement =
createNgElementConstructor(PopupComponent, {injector: this.injector});
// register the custom element with the browser.
customElements.define('popup-element', PopupElement);
}
}

View File

@ -1,22 +0,0 @@
// #docregion
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { PopupService } from './popup.service';
import { PopupComponent } from './popup.component';
// include the PopupService provider,
// but exclude PopupComponent from compilation,
// because it will be added dynamically
@NgModule({
declarations: [AppComponent, PopupComponent],
imports: [BrowserModule, BrowserAnimationsModule],
providers: [PopupService],
bootstrap: [AppComponent],
entryComponents: [PopupComponent],
})
export class AppModule {}

View File

@ -1,58 +0,0 @@
// #docregion
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { AnimationEvent } from '@angular/animations';
import { animate, state, style, transition, trigger } from '@angular/animations';
@Component({
selector: 'my-popup',
template: 'Popup: {{message}}',
host: {
'[@state]': 'state',
'(@state.done)': 'onAnimationDone($event)',
},
animations: [
trigger('state', [
state('opened', style({transform: 'translateY(0%)'})),
state('void, closed', style({transform: 'translateY(100%)', opacity: 0})),
transition('* => *', animate('100ms ease-in')),
])
],
styles: [`
:host {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: #009cff;
height: 48px;
padding: 16px;
display: flex;
align-items: center;
border-top: 1px solid black;
font-size: 24px;
}
`]
})
export class PopupComponent {
private state: 'opened' | 'closed' = 'closed';
@Input()
set message(message: string) {
this._message = message;
this.state = 'opened';
setTimeout(() => this.state = 'closed', 2000);
}
get message(): string { return this._message; }
_message: string;
@Output()
closed = new EventEmitter();
onAnimationDone(e: AnimationEvent) {
if (e.toState === 'closed') {
this.closed.next();
}
}
}

View File

@ -1,54 +0,0 @@
// #docregion
import { ApplicationRef, ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
import { PopupComponent } from './popup.component';
import { NgElementConstructor } from '../elements-dist';
@Injectable()
export class PopupService {
constructor(private injector: Injector,
private applicationRef: ApplicationRef,
private componentFactoryResolver: ComponentFactoryResolver) {}
// Previous dynamic-loading method required you to set up infrastructure
// before adding the popup to the DOM.
showAsComponent(message: string) {
// Create element
const popup = document.createElement('popup-component');
// Create the component and wire it up with the element
const factory = this.componentFactoryResolver.resolveComponentFactory(PopupComponent);
const popupComponentRef = factory.create(this.injector, [], popup);
// Attach to the view so that the change detector knows to run
this.applicationRef.attachView(popupComponentRef.hostView);
// Listen to the close event
popupComponentRef.instance.closed.subscribe(() => {
document.body.removeChild(popup);
this.applicationRef.detachView(popupComponentRef.hostView);
});
// Set the message
popupComponentRef.instance.message = message;
// Add to the DOM
document.body.appendChild(popup);
}
// This uses the new custom-element method to add the popup to the DOM.
showAsElement(message: string) {
// Create element
const popupEl = document.createElement('popup-element');
// Listen to the close event
popupEl.addEventListener('closed', () => document.body.removeChild(popupEl));
// Set the message
popupEl.message = message;
// Add to the DOM
document.body.appendChild(popupEl);
}
}

View File

@ -14,7 +14,7 @@ export class UploadInterceptor implements HttpInterceptor {
if (req.url.indexOf('/upload/file') === -1) {
return next.handle(req);
}
const delay = 300; // TODO: inject delay?
const delay = 300; // Todo: inject delay?
return createUploadEvents(delay);
}
}

View File

@ -6,7 +6,12 @@ declare var jasmine;
import './polyfills';
import 'zone.js/dist/zone-testing';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import { getTestBed } from '@angular/core/testing';
import {

View File

@ -43,7 +43,6 @@ export class PeekABooParentComponent {
this.heroName = 'Windstorm';
this.logger.clear(); // clear log on create
}
this.hookLog = this.logger.logs;
this.logger.tick();
}

View File

@ -6,6 +6,7 @@ import { UserService } from './user.service';
@NgModule({
imports: [ BrowserModule ],
providers: [ UserService ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})

View File

@ -1,9 +0,0 @@
import { NgModule } from '@angular/core';
import { UserService } from './user.service';
@NgModule({
providers: [UserService],
})
export class UserModule {
}

View File

@ -1,7 +0,0 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class UserService {
}

View File

@ -1,8 +0,0 @@
import { Injectable } from '@angular/core';
import { UserModule } from './user.module';
@Injectable({
providedIn: UserModule,
})
export class UserService {
}

View File

@ -3,7 +3,9 @@ import { UserService } from './user.service';
describe('UserService', () => {
beforeEach(() => {
TestBed.configureTestingModule({});
TestBed.configureTestingModule({
providers: [UserService]
});
});
it('should ...', inject([UserService], (service: UserService) => {

View File

@ -5,9 +5,7 @@ export class User {
name: string;
}
@Injectable({
providedIn: 'root',
})
@Injectable()
export class UserService {
constructor() { }

View File

@ -3,7 +3,7 @@
"files": [
"!**/*.d.ts",
"!**/*.js",
"!**/*.[0,1,2].*"
"!**/*.[1,2].*"
],
"file": "src/app/app.component.ts",
"tags": ["providers"]

View File

@ -23,7 +23,7 @@ export class HeroListComponent implements OnInit {
getHeroes() {
this.isLoading = true;
this.heroes = this.heroService.getHeroes()
// TODO: error handling
// Todo: error handling
.pipe(finalize(() => this.isLoading = false));
this.selectedHero = undefined;
}

View File

@ -1,6 +1,6 @@
// #docplaster
// #docregion
// TODO: Feature Componetized like HeroCenter
// TODO SOMEDAY: Feature Componetized like HeroCenter
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';

View File

@ -1,6 +1,6 @@
// #docplaster
// #docregion
// TODO: Feature Componetized like CrisisCenter
// TODO SOMEDAY: Feature Componetized like CrisisCenter
// #docregion rxjs-imports
import { Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';

View File

@ -6,7 +6,7 @@ import { filter, map } from 'rxjs/operators';
const squareOdd = of(1, 2, 3, 4, 5)
.pipe(
filter(n => n % 2 !== 0),
filter(n => n % 2),
map(n => n * n)
);

View File

@ -21,7 +21,12 @@
<script src="node_modules/jasmine-core/lib/jasmine-core/boot.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/zone.js/dist/zone-testing.js"></script>
<script src="node_modules/zone.js/dist/long-stack-trace-zone.js"></script>
<script src="node_modules/zone.js/dist/proxy.js"></script>
<script src="node_modules/zone.js/dist/sync-test.js"></script>
<script src="node_modules/zone.js/dist/jasmine-patch.js"></script>
<script src="node_modules/zone.js/dist/async-test.js"></script>
<script src="node_modules/zone.js/dist/fake-async-test.js"></script>
<!-- #docregion files -->
<script>

View File

@ -59,8 +59,7 @@ describe('Style Guide', function () {
expect(buttons.get(1).getText()).toBe('Hide toast');
});
// temporarily disabled because of a weird issue when used with rxjs v6 with rxjs-compat
xit('03-06', function () {
it('03-06', function () {
browser.get('#/03-06');
let div = element(by.tagName('sg-app > div'));
@ -159,8 +158,7 @@ describe('Style Guide', function () {
expect(input.isPresent()).toBe(true);
});
// temporarily disabled because of a weird issue when used with rxjs v6 with rxjs-compat
xit('07-01', function () {
it('07-01', function () {
browser.get('#/07-01');
let lis = element.all(by.tagName('sg-app > ul > li'));

View File

@ -8,5 +8,6 @@ import { HeroService } from './heroes';
template: `
<toh-heroes></toh-heroes>
`,
providers: [HeroService]
})
export class AppComponent {}

View File

@ -5,9 +5,7 @@ import { Observable, of } from 'rxjs';
import { Hero } from './hero.model';
@Injectable({
providedIn: 'root',
})
@Injectable()
export class HeroService {
getHeroes() {
let heroes: Hero[] = [];

View File

@ -37,8 +37,8 @@ export class ValueService {
// #docregion MasterService
@Injectable()
export class MasterService {
constructor(private valueService: ValueService) { }
getValue() { return this.valueService.getValue(); }
constructor(private masterService: ValueService) { }
getValue() { return this.masterService.getValue(); }
}
// #enddocregion MasterService

View File

@ -15,7 +15,7 @@ describe ('HeroesService (with spies)', () => {
let heroService: HeroService;
beforeEach(() => {
// TODO: spy on other methods too
// Todo: spy on other methods too
httpClientSpy = jasmine.createSpyObj('HttpClient', ['get']);
heroService = new HeroService(<any> httpClientSpy);
});

View File

@ -1,7 +1,7 @@
// #docregion
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'titlecase', pure: true})
@Pipe({name: 'titlecase', pure: false})
/** Transform to Title Case: uppercase the first letter of the words in a string.*/
export class TitleCasePipe implements PipeTransform {
transform(input: string): string {

View File

@ -6,7 +6,12 @@ declare var jasmine;
import './polyfills';
import 'zone.js/dist/zone-testing';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import { getTestBed } from '@angular/core/testing';
import {

View File

@ -22,7 +22,12 @@
<script src="node_modules/jasmine-core/lib/jasmine-core/boot.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/zone.js/dist/zone-testing.js"></script>
<script src="node_modules/zone.js/dist/long-stack-trace-zone.js"></script>
<script src="node_modules/zone.js/dist/proxy.js"></script>
<script src="node_modules/zone.js/dist/sync-test.js"></script>
<script src="node_modules/zone.js/dist/jasmine-patch.js"></script>
<script src="node_modules/zone.js/dist/async-test.js"></script>
<script src="node_modules/zone.js/dist/fake-async-test.js"></script>
<script>
var __spec_files__ = [

View File

@ -1,9 +1,12 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HeroesComponent } from './heroes/heroes.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
import { HeroService } from './hero.service';
import { MessageService } from './message.service';
import { MessagesComponent } from './messages/messages.component';
@NgModule({
@ -18,9 +21,14 @@ import { MessagesComponent } from './messages/messages.component';
FormsModule
],
// #docregion providers
// #docregion providers-heroservice
providers: [
// no need to place any providers due to the `providedIn` flag...
HeroService,
// #enddocregion providers-heroservice
MessageService
// #docregion providers-heroservice
],
// #enddocregion providers-heroservice
// #enddocregion providers
bootstrap: [ AppComponent ]
})

View File

@ -8,9 +8,7 @@ import { Hero } from './hero';
import { HEROES } from './mock-heroes';
// #docregion new
@Injectable({
providedIn: 'root',
})
@Injectable()
export class HeroService {
constructor() { }

View File

@ -14,9 +14,7 @@ import { HEROES } from './mock-heroes';
import { MessageService } from './message.service';
// #enddocregion import-message-service
@Injectable({
providedIn: 'root',
})
@Injectable()
export class HeroService {
// #docregion ctor
@ -26,7 +24,7 @@ export class HeroService {
// #docregion getHeroes, getHeroes-1
getHeroes(): Observable<Hero[]> {
// #enddocregion getHeroes-1
// TODO: send the message _after_ fetching the heroes
// Todo: send the message _after_ fetching the heroes
this.messageService.add('HeroService: fetched heroes');
// #docregion getHeroes-1
return of(HEROES);

View File

@ -1,8 +1,6 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
@Injectable()
export class MessageService {
messages: string[] = [];

View File

@ -7,6 +7,8 @@ import { AppComponent } from './app.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
import { HeroesComponent } from './heroes/heroes.component';
import { HeroService } from './hero.service';
import { MessageService } from './message.service';
import { MessagesComponent } from './messages/messages.component';
// #docregion routing-module
@ -28,6 +30,7 @@ import { AppRoutingModule } from './app-routing.module';
MessagesComponent
],
// #enddocregion dashboard
providers: [ HeroService, MessageService ],
bootstrap: [ AppComponent ]
// #docregion routing-module
})

View File

@ -6,20 +6,20 @@ import { Hero } from './hero';
import { HEROES } from './mock-heroes';
import { MessageService } from './message.service';
@Injectable({ providedIn: 'root' })
@Injectable()
export class HeroService {
constructor(private messageService: MessageService) { }
getHeroes(): Observable<Hero[]> {
// TODO: send the message _after_ fetching the heroes
// Todo: send the message _after_ fetching the heroes
this.messageService.add('HeroService: fetched heroes');
return of(HEROES);
}
// #docregion getHero
getHero(id: number): Observable<Hero> {
// TODO: send the message _after_ fetching the hero
// Todo: send the message _after_ fetching the hero
this.messageService.add(`HeroService: fetched hero id=${id}`);
return of(HEROES.find(hero => hero.id === id));
}

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
@Injectable()
export class MessageService {
messages: string[] = [];

View File

@ -19,6 +19,8 @@ import { HeroesComponent } from './heroes/heroes.component';
// #enddocregion v1
import { HeroSearchComponent } from './hero-search/hero-search.component';
// #docregion v1
import { HeroService } from './hero.service';
import { MessageService } from './message.service';
import { MessagesComponent } from './messages/messages.component';
@NgModule({
@ -47,6 +49,7 @@ import { MessagesComponent } from './messages/messages.component';
HeroSearchComponent
// #docregion v1
],
providers: [ HeroService, MessageService ],
bootstrap: [ AppComponent ]
})
export class AppModule { }

View File

@ -19,7 +19,7 @@ const httpOptions = {
};
// #enddocregion http-options
@Injectable({ providedIn: 'root' })
@Injectable()
export class HeroService {
// #docregion heroesUrl

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
@Injectable()
export class MessageService {
messages: string[] = [];

View File

@ -0,0 +1,19 @@
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2017",
"dom"
]
}
}

View File

@ -22,7 +22,12 @@ module.exports = function(config) {
// zone.js
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/zone-testing.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/zone.js/dist/proxy.js',
'node_modules/zone.js/dist/sync-test.js',
'node_modules/zone.js/dist/jasmine-patch.js',
'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/fake-async-test.js',
// RxJs.
{ pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },

View File

@ -41,7 +41,12 @@ module.exports = function(config) {
// zone.js
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/zone-testing.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/zone.js/dist/proxy.js',
'node_modules/zone.js/dist/sync-test.js',
'node_modules/zone.js/dist/jasmine-patch.js',
'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/fake-async-test.js',
// RxJs
{ pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },

View File

@ -41,7 +41,12 @@ module.exports = function(config) {
// zone.js
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/zone-testing.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/zone.js/dist/proxy.js',
'node_modules/zone.js/dist/sync-test.js',
'node_modules/zone.js/dist/jasmine-patch.js',
'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/fake-async-test.js',
// RxJs
{ pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },

View File

@ -5,7 +5,12 @@ require('core-js/es6');
require('core-js/es7/reflect');
require('zone.js/dist/zone');
require('zone.js/dist/zone-testing');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/proxy');
require('zone.js/dist/sync-test');
require('zone.js/dist/jasmine-patch');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
var appContext = require.context('../src', true, /\.spec\.ts/);

View File

@ -103,7 +103,7 @@ You can control your app compilation by providing template compiler options in t
This option tells the compiler not to produce `.metadata.json` files.
The option is `false` by default.
`.metadata.json` files contain information needed by the template compiler from a `.ts`
`.metadata.json` files contain infomration needed by the template compiler from a `.ts`
file that is not included in the `.d.ts` file produced by the TypeScript compiler. This information contains,
for example, the content of annotations (such as a component's template) which TypeScript
emits to the `.js` file but not to the `.d.ts` file.
@ -118,7 +118,7 @@ include a copy of the information that is in the `.metadata.json` file.
### *strictMetadataEmit*
This option tells the template compiler to report an error to the `.metadata.json`
file if `"skipMetadataEmit"` is `false` . This option is `false` by default. This should only be used when `"skipMetadataEmit"` is `false` and `"skipTemplateCodegen"` is `true`.
file if `"skipMetadataEmit"` is `false` . This option is `false` by default. This should only be used when `"skipMetadataEmit"` is `false` and `"skipTemplateCodeGen"` is `true`.
It is intended to validate the `.metadata.json` files emitted for bundling with an `npm` package. The validation is overly strict and can emit errors for metadata that would never produce an error when used by the template compiler. You can choose to suppress the error emitted by this option for an exported symbol by including `@dynamic` in the comment documenting the symbol.
@ -188,7 +188,7 @@ This option should be set to `false` when using factory summaries.
### *fullTemplateTypeCheck*
This option tells the compiler to enable the [binding expression validation](#binding-expression-validation)
This option tells the compiler to enable the [binding expression validation](#binding-expresion-validation)
phase of the template compiler which uses TypeScript to validate binding expressions.
This option is `false` by default.
@ -204,7 +204,7 @@ JavaScript with [JsDoc](http://usejsdoc.org/) comments needed by the
### *annotationsAs*
Use this option to modify how the Angular specific annotations are emitted to improve tree-shaking. Non-Angular
annotations and decorators are unaffected. Default is `static fields`.
annotations and decorators are unnaffected. Default is `static fields`.
value | description
----------------|-------------------------------------------------------------
@ -215,6 +215,13 @@ value | description
This tells the compiler to print extra information while compiling templates.
### *enableLegacyTemplate*
The use of `<template>` element was deprecated starting in Angular 4.0 in favor of using
`<ng-template>` to avoid colliding with the DOM's element of the same name. Setting this option to
`true` enables the use of the deprecated `<template>` element . This option
is `false` by default. This option might be required by some third-party Angular libraries.
### *disableExpressionLowering*
The Angular template compiler transforms code that is used, or could be used, in an annotation
@ -379,7 +386,7 @@ export function serverFactory() {
})
```
Beginning in version 5, the compiler automatically performs this rewriting while emitting the `.js` file.
Beginning in version 5, the compiler automatically performs this rewritting while emitting the `.js` file.
{@a function-calls}
### Limited function calls
@ -647,7 +654,7 @@ The following are metadata errors you may encounter, with explanations and sugge
<h3 class="no-toc">Expression form not supported</h3>
The compiler encountered an expression it didn't understand while evaluating Angular metadata.
The compiler encountered an expression it didn't understand while evalutating Angular metadata.
Language features outside of the compiler's [restricted expression syntax](#expression-syntax)
can produce this error, as seen in the following example:
@ -1133,12 +1140,12 @@ This error can occur if you use an expression in the `extends` clause of a class
Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](https://github.com/angular/angular/pull/17712#discussion_r132025495).
-->
{@a binding-expression-validation}
{@a binding-expresion-validation}
## Phase 3: binding expression validation
In the validation phase, the Angular template compiler uses the TypeScript compiler to validate the
binding expressions in templates. Enable this phase explicitly by adding the compiler
binding expressions in templates. Enable this phase explicity by adding the compiler
option `"fullTemplateTypeCheck"` in the `"angularCompilerOptions"` of the project's `tsconfig.json` (see
[Angular Compiler Options](#compiler-options)).
@ -1168,7 +1175,7 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
generated by the template compiler that holds contents of the `MyComponent` class template.
Compiler never writes this file to disk. The line and column numbers are relative to the template string
in the `@Component` annotation of the class, `MyComponent` in this case. If a component uses
`templateUrl` instead of `template`, the errors are reported in the HTML file referenced by the
`templateUrl` instead of `template`, the errors are reported in the HTML file refereneced by the
`templateUrl` instead of a synthetic file.
The error location is the beginning of the text node that contains the interpolation expression with

View File

@ -1,180 +0,0 @@
# Introduction to components
<img src="generated/images/guide/architecture/hero-component.png" alt="Component" class="left">
A _component_ controls a patch of screen called a *view*. For example, individual components define and control each of the following views from the [Tutorial](tutorial/index):
* The app root with the navigation links.
* The list of heroes.
* The hero editor.
You define a component's application logic&mdash;what it does to support the view&mdash;inside a class. The class interacts with the view through an API of properties and methods.
For example, the `HeroListComponent` has a `heroes` property that returns an array of heroes that it acquires from a service. `HeroListComponent` also has a `selectHero()` method that sets a `selectedHero` property when the user clicks to choose a hero from that list.
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (class)" region="class"></code-example>
Angular creates, updates, and destroys components as the user moves through the application. Your app can take action at each moment in this lifecycle through optional [lifecycle hooks](guide/lifecycle-hooks), like `ngOnInit()`.
<hr/>
## Component metadata
<img src="generated/images/guide/architecture/metadata.png" alt="Metadata" class="left">
The `@Component` decorator identifies the class immediately below it as a component class, and specifies its metadata. In the example code below, you can see that `HeroListComponent` is just a class, with no special Angular notation or syntax at all. It's not a component until mark it as one with the `@Component` decorator.
The metadata for a component tells Angular where to get the major building blocks it needs to create and present the component and its view. In particular, it associates a _template_ with the component, either directly with inline code, or by reference. Together, the component and its template describe a _view_.
In addition to containing or pointing to the template, the `@Component` metadata configures, for example, how the component can be referenced in HTML and what services it requires.
Here's an example of basic metadata for `HeroListComponent`:
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
This example shows some of the most useful `@Component` configuration options:
* `selector`: A CSS selector that tells Angular to create and insert an instance of this component wherever it finds the corresponding tag in template HTML. For example, if an app's HTML contains `<app-hero-list></app-hero-list>`, then
Angular inserts an instance of the `HeroListComponent` view between those tags.
* `templateUrl`: The module-relative address of this component's HTML template. Alternatively, you can provide the HTML template inline, as the value of the `template` property. This template defines the component's _host view_.
* `providers`: An array of **dependency injection providers** for services that the component requires. In the example, this tells Angular that the component's constructor requires a `HeroService` instance
in order to get the list of heroes to display.
<hr/>
## Templates and views
<img src="generated/images/guide/architecture/template.png" alt="Template" class="left">
You define a component's view with its companion template. A template is a form of HTML that tells Angular how to render the component.
Views are typically arranged hierarchically, allowing you to modify or show and hide entire UI sections or pages as a unit. The template immediately associated with a component defines that component's _host view_. The component can also define a _view hierarchy_, which contains _embedded views_, hosted by other components.
<figure>
<img src="generated/images/guide/architecture/component-tree.png" alt="Component tree" class="left">
</figure>
A view hierarchy can include views from components in the same NgModule, but it also can (and often does) include views from components that are defined in different NgModules.
## Template syntax
A template looks like regular HTML, except that it also contains Angular [template syntax](guide/template-syntax), which alters the HTML based on your app's logic and the state of app and DOM data. Your template can use _data binding_ to coordinate the app and DOM data, _pipes_ to transform data before it is displayed, and _directives_ to apply app logic to what gets displayed.
For example, here is a template for the Tutorial's `HeroListComponent`:
<code-example path="architecture/src/app/hero-list.component.html" title="src/app/hero-list.component.html"></code-example>
This template uses typical HTML elements like `<h2>` and `<p>`, and also includes Angular template-syntax elements, `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and `<app-hero-detail>`. The template-syntax elements tell Angular how to render the HTML to the screen, using program logic and data.
* The `*ngFor` directive tells Angular to iterate over a list.
* The `{{hero.name}}`, `(click)`, and `[hero]` bind program data to and from the DOM, responding to user input. See more about [data binding](#data-binding) below.
* The `<app-hero-detail>` tag in the example is an element that represents a new component, `HeroDetailComponent`. The `HeroDetailComponent` (code not shown) is a child component of the `HeroListComponent` that defines the Hero-detail view. Notice how custom components like this mix seamlessly with native HTML in the same layouts.
### Data binding
Without a framework, you would be responsible for pushing data values into the HTML controls and turning user responses into actions and value updates. Writing such push/pull logic by hand is tedious, error-prone, and a nightmare to read, as any experienced jQuery programmer can attest.
Angular supports *two-way data binding*, a mechanism for coordinating parts of a template with parts of a component. Add binding markup to the template HTML to tell Angular how to connect both sides.
The following diagram shows the four forms of data binding markup. Each form has a direction&mdash;to the DOM, from the DOM, or in both directions.
<figure>
<img src="generated/images/guide/architecture/databinding.png" alt="Data Binding" class="left">
</figure>
This example from the `HeroListComponent` template uses three of these forms:
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" title="src/app/hero-list.component.html (binding)" region="binding"></code-example>
* The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation)
displays the component's `hero.name` property value within the `<li>` element.
* The `[hero]` [*property binding*](guide/template-syntax#property-binding) passes the value of `selectedHero` from
the parent `HeroListComponent` to the `hero` property of the child `HeroDetailComponent`.
* The `(click)` [*event binding*](guide/user-input#binding-to-user-input-events) calls the component's `selectHero` method when the user clicks a hero's name.
**Two-way data binding** is an important fourth form that combines property and event binding in a single notation. Here's an example from the `HeroDetailComponent` template that uses two-way data binding with the `ngModel` directive:
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
In two-way binding, a data property value flows to the input box from the component as with property binding.
The user's changes also flow back to the component, resetting the property to the latest value,
as with event binding.
Angular processes *all* data bindings once per JavaScript event cycle,
from the root of the application component tree through all child components.
<figure>
<img src="generated/images/guide/architecture/component-databinding.png" alt="Data Binding" class="left">
</figure>
Data binding plays an important role in communication between a template and its component, and is also important for communication between parent and child components.
<figure>
<img src="generated/images/guide/architecture/parent-child-binding.png" alt="Parent/Child binding" class="left">
</figure>
### Pipes
Angular pipes let you declare display-value transformations in your template HTML. A class with the `@Pipe` decorator defines a function that transforms input values to output values for display in a view.
Angular defines various pipes, such as the [date](https://angular.io/api/common/DatePipe) pipe and [currency](https://angular.io/api/common/CurrencyPipe) pipe; for a complete list, see the [Pipes API list](https://angular.io/api?type=pipe). You can also define new pipes.
To specify a value transformation in an HTML template, use the [pipe operator (|)](https://angular.io/guide/template-syntax#pipe):
`{{interpolated_value | pipe_name}}`
You can chain pipes, sending the output of one pipe function to be transformed by another pipe function. A pipe can also take arguments that control how it performs its transformation. For example, you can pass the desired format to the `date` pipe:
```
<!-- Default format: output 'Jun 15, 2015'-->
<p>Today is {{today | date}}</p>
<!-- fullDate format: output 'Monday, June 15, 2015'-->
<p>The date is {{today | date:'fullDate'}}</p>
<!-- shortTime format: output '9:43 AM'-->
<p>The time is {{today | date:'shortTime'}}</p>
```
<hr/>
### Directives
<img src="generated/images/guide/architecture/directive.png" alt="Directives" class="left">
Angular templates are *dynamic*. When Angular renders them, it transforms the DOM according to the instructions given by *directives*. A directive is a class with a `@Directive` decorator.
A component is technically a directive - but components are so distinctive and central to Angular applications that Angular defines the `@Component` decorator, which extends the `@Directive` decorator with template-oriented features.
There are two kinds of directives besides components: _structural_ and _attribute_ directives. Just as for components, the metadata for a directive associates the class with a `selector` that you use to insert it into HTML. In templates, directives typically appear within an element tag as attributes, either by name or as the target of an assignment or a binding.
#### Structural directives
Structural directives alter layout by adding, removing, and replacing elements in DOM. The example template uses two built-in structural directives to add application logic to how the view is rendered:
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" title="src/app/hero-list.component.html (structural)" region="structural"></code-example>
* [`*ngFor`](guide/displaying-data#ngFor) is an iterative; it tells Angular to stamp out one `<li>` per hero in the `heroes` list.
* [`*ngIf`](guide/displaying-data#ngIf) is a conditional; it includes the `HeroDetail` component only if a selected hero exists.
#### Attribute directives
Attribute directives alter the appearance or behavior of an existing element.
In templates they look like regular HTML attributes, hence the name.
The `ngModel` directive, which implements two-way data binding, is an example of an attribute directive. `ngModel` modifies the behavior of an existing element (typically an `<input>`) by setting its display value property and responding to change events.
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
Angular has more pre-defined directives that either alter the layout structure
(for example, [ngSwitch](guide/template-syntax#ngSwitch))
or modify aspects of DOM elements and components
(for example, [ngStyle](guide/template-syntax#ngStyle) and [ngClass](guide/template-syntax#ngClass)).
You can also write your own directives. Components such as `HeroListComponent` are one kind of custom directive. You can also create custom structural and attribute directives.
<!-- PENDING: link to where to learn more about other kinds! -->

View File

@ -1,107 +0,0 @@
# Introduction to modules
<img src="generated/images/guide/architecture/module.png" alt="Module" class="left">
Angular apps are modular and Angular has its own modularity system called _NgModules_. An NgModule is a container for a cohesive block of code dedicated to an application domain, a workflow, or a closely related set of capabilities. It can contain components, service providers, and other code files whose scope is defined by the containing NgModule. It can import functionality that is exported from other NgModules, and export selected functionality for use by other NgModules.
Every Angular app has at least one NgModule class, [the _root module_](guide/bootstrapping), which is conventionally named `AppModule` and resides in a file named `app.module.ts`. You launch your app by *bootstrapping* the root NgModule.
While a small application might have only one NgModule, most apps have many more _feature modules_. The _root_ NgModule for an app is so named because it can include child NgModules in a hierarchy of any depth.
## NgModule metadata
An NgModule is defined as a class decorated with `@NgModule`. The `@NgModule` decorator is a function that takes a single metadata object, whose properties describe the module. The most important properties are as follows.
* `declarations`&mdash;The [components](guide/architecture-components), _directives_, and _pipes_ that belong to this NgModule.
* `exports`&mdash;The subset of declarations that should be visible and usable in the _component templates_ of other NgModules.
* `imports`&mdash;Other modules whose exported classes are needed by component templates declared in _this_ NgModule.
* `providers`&mdash;Creators of [services](guide/architecture-services) that this NgModule contributes to the global collection of services; they become accessible in all parts of the app. (You can also specify providers at the component level, which is often preferred.)
* `bootstrap`&mdash;The main application view, called the _root component_, which hosts all other app views. Only the _root NgModule_ should set this `bootstrap` property.
Here's a simple root NgModule definition:
<code-example path="architecture/src/app/mini-app.ts" region="module" title="src/app/app.module.ts" linenums="false"></code-example>
<div class="l-sub-section">
The `export` of `AppComponent` is just to show how to export; it isn't actually necessary in this example. A root NgModule has no reason to _export_ anything because other modules don't need to _import_ the root NgModule.
</div>
## NgModules and components
NgModules provide a _compilation context_ for their components. A root NgModule always has a root component that is created during bootstrap, but any NgModule can include any number of additional components, which can be loaded through the router or created through the template. The components that belong to an NgModule share a compilation context.
<figure>
<img src="generated/images/guide/architecture/compilation-context.png" alt="Component compilation context" class="left">
</figure>
<br class="clear">
A component and its template together define a _view_. A component can contain a _view hierarchy_, which allows you to define arbitrarily complex areas of the screen that can be created, modified, and destroyed as a unit. A view hierarchy can mix views defined in components that belong to different NgModules. This is often the case, especially for UI libraries.
<figure>
<img src="generated/images/guide/architecture/view-hierarchy.png" alt="View hierarchy" class="left">
</figure>
<br class="clear">
When you create a component, it is associated directly with a single view, called the _host view_. The host view can be the root of a view hierarchy, which can contain _embedded views_, which are in turn the host views of other components. Those components can be in the same NgModule, or can be imported from other NgModules. Views in the tree can be nested to any depth.
<div class="l-sub-section">
The hierarchical structure of views is a key factor in the way Angular detects and responds to changes in the DOM and app data.
</div>
## NgModules and JavaScript modules
The NgModule system is different from and unrelated to the JavaScript (ES2015) module system for managing collections of JavaScript objects. These are two different and _complementary_ module systems. You can use them both to write your apps.
In JavaScript each _file_ is a module and all objects defined in the file belong to that module.
The module declares some objects to be public by marking them with the `export` key word.
Other JavaScript modules use *import statements* to access public objects from other modules.
<code-example path="architecture/src/app/app.module.ts" region="imports" linenums="false"></code-example>
<code-example path="architecture/src/app/app.module.ts" region="export" linenums="false"></code-example>
<div class="l-sub-section">
<a href="http://exploringjs.com/es6/ch_modules.html">Learn more about the JavaScript module system on the web.</a>
</div>
## Angular libraries
<img src="generated/images/guide/architecture/library-module.png" alt="Component" class="left">
Angular ships as a collection of JavaScript modules. You can think of them as library modules. Each Angular library name begins with the `@angular` prefix. Install them with the `npm` package manager and import parts of them with JavaScript `import` statements.
<br class="clear">
For example, import Angular's `Component` decorator from the `@angular/core` library like this:
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
You also import NgModules from Angular _libraries_ using JavaScript import statements:
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module" linenums="false"></code-example>
In the example of the simple root module above, the application module needs material from within the `BrowserModule`. To access that material, add it to the `@NgModule` metadata `imports` like this.
<code-example path="architecture/src/app/mini-app.ts" region="ngmodule-imports" linenums="false"></code-example>
In this way you're using both the Angular and JavaScript module systems _together_. Although it's easy to confuse the two systems, which share the common vocabulary of "imports" and "exports", you will become familiar with the different contexts in which they are used.
<div class="l-sub-section">
Learn more from the [NgModules](guide/ngmodules) page.
</div>
<hr/>

View File

@ -1,48 +0,0 @@
# Next steps: tools and techniques
Once you have understood the basic building blocks, you can begin to learn more about the features and tools that are available to help you develop and deliver Angular applications. Angular provides a lot more features and services that are covered in this documentation.
#### Responsive programming tools
* [Lifecycle hooks](guide/lifecycle-hooks): Tap into key moments in the lifetime of a component, from its creation to its destruction, by implementing the lifecycle hook interfaces.
* [Observables and event processing](guide/observables): How to use observables with components and services to publish and subscribe to messages of any type, such as user-interaction events and asynchronous operation results.
#### Client-server interaction tools
* [HTTP](guide/http): Communicate with a server to get data, save data, and invoke server-side actions with an HTTP client.
* [Server-side Rendering](guide/universal): Angular Universal generates static application pages on the server through server-side rendering (SSR). This allows you to run your Angular app on the server in order to improve performance and show the first page quickly on mobile and low-powered devices, and also facilitate web crawlers.
* [Service Workers](guide/service-worker-intro): A service worker is a script that runs in the web browser and manages caching for an application. Service workers function as a network proxy. They intercept outgoing HTTP requests and can, for example, deliver a cached response if one is available. You can significantly improve the user experience by using a service worker to reduce dependency on the network.
#### Domain-specific libraries
* [Animations](guide/animations): Animate component behavior
without deep knowledge of animation techniques or CSS with Angular's animation library.
* [Forms](guide/forms): Support complex data entry scenarios with HTML-based validation and dirty checking.
#### Support for the development cycle
* [Testing Platform](guide/testing): Run unit tests on your application parts as they interact with the Angular framework.
* [Internationalization](guide/i18n): Angular's internationalization (i18n) tools can help you make your app available in multiple languages.
* [Compilation](guide/aot-compiler): Angular provides just-in-time (JIT) compilation for the development environment, and ahead-of-time (AOT) compilation for the production environment.
* [Security guidelines](guide/security): Learn about Angular's built-in protections against common web-app vulnerabilities and attacks such as cross-site scripting attacks.
#### Setup and deployment tools
* [Setup for local development](guide/setup): Learn how to set up a new project for development with QuickStart.
* [Installation](guide/npm-packages): The [Angular CLI](https://cli.angular.io/), Angular applications, and Angular itself depend on features and functionality provided by libraries that are available as [npm](https://docs.npmjs.com/) packages.
* [Typescript Configuration](guide/typescript-configuration): TypeScript is the primary language for Angular application development.
* [Browser support](guide/browser-support): Learn how to make your apps compatible across a wide range of browsers.
* [Deployment](guide/deployment): Learn techniques for deploying your Angular application to a remote server.
<hr/>

View File

@ -1,76 +0,0 @@
# Introduction to services and dependency injection
<img src="generated/images/guide/architecture/service.png" alt="Service" class="left">
_Service_ is a broad category encompassing any value, function, or feature that an app needs. A service is typically a class with a narrow, well-defined purpose. It should do something specific and do it well.
<br class="clear">
Angular distinguishes components from services in order to increase modularity and reusability.
* By separating a component's view-related functionality 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. It should present properties and methods for data binding, in order to mediate between the view (rendered by the template) and the application logic (which often includes some notion of a _model_).
* A component should not need to define things like how to fetch data from the server, validate user input, or log directly to the console. Instead, it can delegate such tasks to services. By defining that kind of processing task in an injectable service class, you make it available to any component. You can also make your app more adaptable by injecting different providers of the same kind of service, as appropriate in different circumstances.
Angular doesn't *enforce* these principles. Angular does help you *follow* these principles by making it easy to factor your
application logic into services and make those services available to components through *dependency injection*.
## Service examples
Here's an example of a service class that logs to the browser console:
<code-example path="architecture/src/app/logger.service.ts" linenums="false" title="src/app/logger.service.ts (class)" region="class"></code-example>
Services can depend on other services. For example, here's a `HeroService` that depends on the `Logger` service, and also uses `BackendService` to get heroes. That service in turn might depend on the `HttpClient` service to fetch heroes asynchronously from a server.
<code-example path="architecture/src/app/hero.service.ts" linenums="false" title="src/app/hero.service.ts (class)" region="class"></code-example>
<hr/>
## Dependency injection
<img src="generated/images/guide/architecture/dependency-injection.png" alt="Service" class="left">
Components consume services; that is, you can *inject* a service into a component, giving the component access to that service class.
To define a class as a service in Angular, use the `@Injectable` decorator to provide the metadata that allows Angular to inject it into a component as a *dependency*.
Similarly, use the `@Injectable` decorator to indicate that a component or other class (such as another service, a pipe, or an NgModule) _has_ a dependency. A dependency doesn't have to be a service&mdash;it could be a function, for example, or a value.
*Dependency injection* (often called DI) is wired into the Angular framework and used everywhere to provide new components with the services or other things they need.
* The *injector* is the main mechanism. You don't have to create an Angular injector. Angular creates an application-wide injector for you during the bootstrap process.
* The injector maintains a *container* of dependency instances that it has already created, and reuses them if possible.
* A *provider* is a recipe for creating a dependency. For a service, this is typically the service class itself. For any dependency you need in your app, you must register a provider with the app's injector, so that the injector can use it to create new instances.
When Angular creates a new instance of a component class, it determines which services or other dependencies that component needs by looking at the types of its constructor parameters. For example, the constructor of `HeroListComponent` needs a `HeroService`:
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (constructor)" region="ctor"></code-example>
When Angular discovers that a component depends on a service, it first checks if the injector already has any existing instances of that service. If a requested service instance does not yet exist, the injector makes one using the registered provider, and adds it to the injector before returning the service to Angular.
When all requested services have been resolved and returned, Angular can call the component's constructor with those services as arguments.
The process of `HeroService` injection looks something like this:
<figure>
<img src="generated/images/guide/architecture/injector-injects.png" alt="Service" class="left">
</figure>
### Providing services
You must register at least one *provider* of any service you are going to use. You can register providers in modules or in components.
* When you add providers to the [root module](guide/architecture-modules), the same instance of a service is available to all components in your app.
<code-example path="architecture/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (module providers)" region="providers"></code-example>
* When you register a provider at the component level, you get a new instance of the
service with each new instance of that component. At the component level, register a service provider in the `providers` property of the `@Component` metadata:
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (component providers)" region="providers"></code-example>
For more detailed information, see the [Dependency Injection](guide/dependency-injection) section.
<hr/>

View File

@ -1,137 +1,533 @@
# Architecture overview
# Architecture Overview
Angular is a platform and framework for building client applications in HTML and TypeScript.
Angular is itself written in TypeScript. It implements core and optional functionality as a set of TypeScript libraries that you import into your apps.
Angular is a framework for building client applications in HTML and
either JavaScript or a language like TypeScript that compiles to JavaScript.
The basic building blocks of an Angular application are _NgModules_, which provide a compilation context for _components_. NgModules collect related code into functional sets; an Angular app is defined by a set of NgModules. An app always has at least a _root module_ that enables bootstrapping, and typically has many more _feature modules_.
The framework consists of several libraries, some of them core and some optional.
* Components define *views*, which are sets of screen elements that Angular can choose among and modify according to your program logic and data. Every app has at least a root component.
You write Angular applications by composing HTML *templates* with Angularized markup,
writing *component* classes to manage those templates, adding application logic in *services*,
and boxing components and services in *modules*.
* Components use *services*, which provide specific functionality not directly related to views. Service providers can be *injected* into components as *dependencies*, making your code modular, reusable, and efficient.
Then you launch the app by *bootstrapping* the _root module_.
Angular takes over, presenting your application content in a browser and
responding to user interactions according to the instructions you've provided.
Both components and services are simply classes, with *decorators* that mark their type and provide metadata that tells Angular how to use them.
* The metadata for a component class associates it with a *template* that defines a view. A template combines ordinary HTML with Angular *directives* and *binding markup* that allow Angular to modify the HTML before rendering it for display.
* The metadata for a service class provides the information Angular needs to make it available to components through *Dependency Injection (DI)*.
An app's components typically define many views, arranged hierarchically. Angular provides the `Router` service to help you define navigation paths among views. The router provides sophisticated in-browser navigational capabilities.
## Modules
Angular defines the `NgModule`, which differs from and complements the JavaScript (ES2015) module. An NgModule declares a compilation context for a set of components that is dedicated to an application domain, a workflow, or a closely related set of capabilities. An NgModule can associate its components with related code, such as services, to form functional units.
Every Angular app has a _root module_, conventionally named `AppModule`, which provides the bootstrap mechanism that launches the application. An app typically contains many functional modules.
Like JavaScript modules, NgModules can import functionality from other NgModules, and allow their own functionality to be exported and used by other NgModules. For example, to use the router service in your app, you import the `Router` NgModule.
Organizing your code into distinct functional modules helps in managing development of complex applications, and in designing for reusability. In addition, this technique lets you take advantage of _lazy-loading_&mdash;that is, loading modules on demand&mdash;in order to minimize the amount of code that needs to be loaded at startup.
<div class="l-sub-section">
For a more detailed discussion, see [Introduction to modules](guide/architecture-modules).
</div>
## Components
Every Angular application has at least one component, the *root component* that connects a component hierarchy with the page DOM. Each component defines a class that contains application data and logic, and is associated with an HTML *template* that defines a view to be displayed in a target environment.
The `@Component` decorator identifies the class immediately below it as a component, and provides the template and related component-specific metadata.
<div class="l-sub-section">
Decorators are functions that modify JavaScript classes. Angular defines a number of such decorators that attach specific kinds of metadata to classes, so that it knows what those classes mean and how they should work.
<a href="https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841#.x5c2ndtx0">Learn more about decorators on the web.</a>
</div>
### Templates, directives, and data binding
A template combines HTML with Angular markup that can modify the HTML elements before they are displayed.
Template *directives* provide program logic, and *binding markup* connects your application data and the document object model (DOM).
* *Event binding* lets your app respond to user input in the target environment by updating your application data.
* *Property binding* lets you interpolate values that are computed from your application data into the HTML.
Before a view is displayed, Angular evaluates the directives and resolves the binding syntax in the template to modify the HTML elements and the DOM, according to your program data and logic. Angular supports *two-way data binding*, meaning that changes in the DOM, such as user choices, can also be reflected back into your program data.
Your templates can also use *pipes* to improve the user experience by transforming values for display. Use pipes to display, for example, dates and currency values in a way appropriate to the user's locale. Angular provides predefined pipes for common transformations, and you can also define your own.
<div class="l-sub-section">
For a more detailed discussion of these concepts, see [Introduction to components](guide/architecture-components).
</div>
{@a dependency-injection}
## Services and dependency injection
For data or logic that is not associated with a specific view, and that you want to share across components, you create a *service* class. A service class definition is immediately preceded by the `@Injectable` decorator. The decorator provides the metadata that allows your service to be *injected* into client components as a dependency.
*Dependency injection* (or DI) lets you keep your component classes lean and efficient. They don't fetch data from the server, validate user input, or log directly to the console; they delegate such tasks to services.
<div class="l-sub-section">
For a more detailed discusssion, see [Introduction to services and DI](guide/architecture-services).
</div>
### Routing
The Angular `Router` NgModule provides a service that lets you define a navigation path among the different application states and view hierarchies in your app. It is modeled on the familiar browser navigation conventions:
* Enter a URL in the address bar and the browser navigates to a corresponding page.
* Click links on the page and the browser navigates to a new page.
* Click the browser's back and forward buttons and the browser navigates backward and forward through the history of pages you've seen.
The router maps URL-like paths to views instead of pages. When a user performs an action, such as clicking a link, that would load a new page in the browser, the router intercepts the browser's behavior, and shows or hides view hierarchies.
If the router determines that the current application state requires particular functionality, and the module that defines it has not been loaded, the router can _lazy-load_ the module on demand.
The router interprets a link URL according to your app's view navigation rules and data state. You can navigate to new views when the user clicks a button, selects from a drop box, or in response to some other stimulus from any source. The Router logs activity in the browser's history journal, so the back and forward buttons work as well.
To define navigation rules, you associate *navigation paths* with your components. A path uses a URL-like syntax that integrates your program data, in much the same way that template syntax integrates your views with your program data. You can then apply program logic to choose which views to show or to hide, in response to user input and your own access rules.
<div class="l-sub-section">
For a more detailed discussion, see [Routing and navigation](guide/router).
</div>
<hr/>
## What's next
You've learned the basics about the main building blocks of an Angular application. The following diagram shows how these basic pieces are related.
Of course, there is more to it than this.
You'll learn the details in the pages that follow. For now, focus on the big picture.
<figure>
<img src="generated/images/guide/architecture/overview2.png" alt="overview">
</figure>
* Together, a component and template define an Angular view.
* A decorator on a component class adds the metadata, including a pointer to the associated template.
* Directives and binding markup in a component's template modify views based on program data and logic.
* The dependency injector provides services to a component, such as the router service that lets you define navigation among views.
<div class="l-sub-section">
Each of these subjects is introduced in more detail in the following pages.
The code referenced on this page is available as a <live-example></live-example>.
* [Modules](guide/architecture-modules)
* [Components](guide/architecture-components)
* [Templates](guide/architecture-components#templates-and-views)
* [Metadata](guide/architecture-components#component-metadata)
* [Data binding](guide/architecture-components#data-binding)
* [Directives](guide/architecture-components#directives)
* [Pipes](guide/architecture-components#pipes)
* [Services and dependency injection](guide/architecture-services)
</div>
## Modules
<img src="generated/images/guide/architecture/module.png" alt="Component" class="left">
Angular apps are modular and Angular has its own modularity system called _NgModules_.
NgModules are a big deal.
This page introduces modules; the [NgModules](guide/ngmodules) pages
relating to NgModules covers them in detail.
<br class="clear">
Every Angular app has at least one NgModule class, [the _root module_](guide/bootstrapping "Bootstrapping"),
conventionally named `AppModule`.
While the _root module_ may be the only module in a small application, most apps have many more
_feature modules_, each a cohesive block of code dedicated to an application domain,
a workflow, or a closely related set of capabilities.
An NgModule, whether a _root_ or _feature_, is a class with an `@NgModule` decorator.
<div class="l-sub-section">
Note that the code referenced on these pages is available as a <live-example></live-example>.
Decorators are functions that modify JavaScript classes.
Angular has many decorators that attach metadata to classes so that it knows
what those classes mean and how they should work.
<a href="https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841#.x5c2ndtx0">
Learn more</a> about decorators on the web.
</div>
When you are familiar with these fundamental building blocks, you can explore them in more detail in the documentation. To learn about more tools and techniques that are available to help you build and deploy Angular applications, see [Next steps](guide/architecture-next-steps).
`NgModule` is a decorator function that takes a single metadata object whose properties describe the module.
The most important properties are:
* `declarations` - the _view classes_ that belong to this module.
Angular has three kinds of view classes: [components](guide/architecture#components), [directives](guide/architecture#directives), and [pipes](guide/pipes).
* `exports` - the subset of declarations that should be visible and usable in the component [templates](guide/architecture#templates) of other modules.
* `imports` - other modules whose exported classes are needed by component templates declared in _this_ module.
* `providers` - creators of [services](guide/architecture#services) that this module contributes to
the global collection of services; they become accessible in all parts of the app.
* `bootstrap` - the main application view, called the _root component_,
that hosts all other app views. Only the _root module_ should set this `bootstrap` property.
Here's a simple root module:
<code-example path="architecture/src/app/mini-app.ts" region="module" title="src/app/app.module.ts" linenums="false"></code-example>
<div class="l-sub-section">
The `export` of `AppComponent` is just to show how to use the `exports` array to export a component; it isn't actually necessary in this example. A root module has no reason to _export_ anything because other components don't need to _import_ the root module.
</div>
Launch an application by _bootstrapping_ its root module.
During development you're likely to bootstrap the `AppModule` in a `main.ts` file like this one.
<code-example path="architecture/src/main.ts" title="src/main.ts" linenums="false"></code-example>
### NgModules vs. JavaScript modules
The NgModule &mdash; a class decorated with `@NgModule` &mdash; is a fundamental feature of Angular.
JavaScript also has its own module system for managing collections of JavaScript objects.
It's completely different and unrelated to the NgModule system.
In JavaScript each _file_ is a module and all objects defined in the file belong to that module.
The module declares some objects to be public by marking them with the `export` key word.
Other JavaScript modules use *import statements* to access public objects from other modules.
<code-example path="architecture/src/app/app.module.ts" region="imports" linenums="false"></code-example>
<code-example path="architecture/src/app/app.module.ts" region="export" linenums="false"></code-example>
<div class="l-sub-section">
<a href="http://exploringjs.com/es6/ch_modules.html">Learn more about the JavaScript module system on the web.</a>
</div>
These are two different and _complementary_ module systems. Use them both to write your apps.
### Angular libraries
<img src="generated/images/guide/architecture/library-module.png" alt="Component" class="left">
Angular ships as a collection of JavaScript modules. You can think of them as library modules.
Each Angular library name begins with the `@angular` prefix.
You install them with the **npm** package manager and import parts of them with JavaScript `import` statements.
<br class="clear">
For example, import Angular's `Component` decorator from the `@angular/core` library like this:
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
You also import NgModules from Angular _libraries_ using JavaScript import statements:
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module" linenums="false"></code-example>
In the example of the simple root module above, the application module needs material from within that `BrowserModule`. To access that material, add it to the `@NgModule` metadata `imports` like this.
<code-example path="architecture/src/app/mini-app.ts" region="ngmodule-imports" linenums="false"></code-example>
In this way you're using both the Angular and JavaScript module systems _together_.
It's easy to confuse the two systems because they share the common vocabulary of "imports" and "exports".
Hang in there. The confusion yields to clarity with time and experience.
<div class="l-sub-section">
Learn more from the [NgModules](guide/ngmodules) page.
</div>
<hr/>
## Components
<img src="generated/images/guide/architecture/hero-component.png" alt="Component" class="left">
A _component_ controls a patch of screen called a *view*.
For example, the following views are controlled by components:
* The app root with the navigation links.
* The list of heroes.
* The hero editor.
You define a component's application logic&mdash;what it does to support the view&mdash;inside a class.
The class interacts with the view through an API of properties and methods.
{@a component-code}
For example, this `HeroListComponent` has a `heroes` property that returns an array of heroes
that it acquires from a service.
`HeroListComponent` also has a `selectHero()` method that sets a `selectedHero` property when the user clicks to choose a hero from that list.
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (class)" region="class"></code-example>
Angular creates, updates, and destroys components as the user moves through the application.
Your app can take action at each moment in this lifecycle through optional [lifecycle hooks](guide/lifecycle-hooks), like `ngOnInit()` declared above.
<hr/>
## Templates
<img src="generated/images/guide/architecture/template.png" alt="Template" class="left">
You define a component's view with its companion **template**. A template is a form of HTML
that tells Angular how to render the component.
A template looks like regular HTML, except for a few differences. Here is a
template for our `HeroListComponent`:
<code-example path="architecture/src/app/hero-list.component.html" title="src/app/hero-list.component.html"></code-example>
Although this template uses typical HTML elements like `<h2>` and `<p>`, it also has some differences. Code like `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and `<app-hero-detail>` uses Angular's [template syntax](guide/template-syntax).
In the last line of the template, the `<app-hero-detail>` tag is a custom element that represents a new component, `HeroDetailComponent`.
The `HeroDetailComponent` is a *different* component than the `HeroListComponent` you've been reviewing.
The `HeroDetailComponent` (code not shown) presents facts about a particular hero, the
hero that the user selects from the list presented by the `HeroListComponent`.
The `HeroDetailComponent` is a **child** of the `HeroListComponent`.
<img src="generated/images/guide/architecture/component-tree.png" alt="Metadata" class="left">
Notice how `<app-hero-detail>` rests comfortably among native HTML elements. Custom components mix seamlessly with native HTML in the same layouts.
<hr class="clear"/>
## Metadata
<img src="generated/images/guide/architecture/metadata.png" alt="Metadata" class="left">
Metadata tells Angular how to process a class.
<br class="clear">
[Looking back at the code](guide/architecture#component-code) for `HeroListComponent`, you can see that it's just a class.
There is no evidence of a framework, no "Angular" in it at all.
In fact, `HeroListComponent` really is *just a class*. It's not a component until you *tell Angular about it*.
To tell Angular that `HeroListComponent` is a component, attach **metadata** to the class.
In TypeScript, you attach metadata by using a **decorator**.
Here's some metadata for `HeroListComponent`:
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
Here is the `@Component` decorator, which identifies the class
immediately below it as a component class.
The `@Component` decorator takes a required configuration object with the
information Angular needs to create and present the component and its view.
Here are a few of the most useful `@Component` configuration options:
* `selector`: CSS selector that tells Angular to create and insert an instance of this component
where it finds a `<app-hero-list>` tag in *parent* HTML.
For example, if an app's HTML contains `<app-hero-list></app-hero-list>`, then
Angular inserts an instance of the `HeroListComponent` view between those tags.
* `templateUrl`: module-relative address of this component's HTML template, shown [above](guide/architecture#templates).
* `providers`: array of **dependency injection providers** for services that the component requires.
This is one way to tell Angular that the component's constructor requires a `HeroService`
so it can get the list of heroes to display.
<img src="generated/images/guide/architecture/template-metadata-component.png" alt="Metadata" class="left">
The metadata in the `@Component` tells Angular where to get the major building blocks you specify for the component.
The template, metadata, and component together describe a view.
Apply other metadata decorators in a similar fashion to guide Angular behavior.
`@Injectable`, `@Input`, and `@Output` are a few of the more popular decorators.
<br class="clear">
The architectural takeaway is that you must add metadata to your code
so that Angular knows what to do.
<hr/>
## Data binding
Without a framework, you would be responsible for pushing data values into the HTML controls and turning user responses
into actions and value updates. Writing such push/pull logic by hand is tedious, error-prone, and a nightmare to
read as any experienced jQuery programmer can attest.
<img src="generated/images/guide/architecture/databinding.png" alt="Data Binding" class="left">
Angular supports **data binding**,
a mechanism for coordinating parts of a template with parts of a component.
Add binding markup to the template HTML to tell Angular how to connect both sides.
As the diagram shows, there are four forms of data binding syntax. Each form has a direction &mdash; to the DOM, from the DOM, or in both directions.
<br class="clear">
The `HeroListComponent` [example](guide/architecture#templates) template has three forms:
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" title="src/app/hero-list.component.html (binding)" region="binding"></code-example>
* The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation)
displays the component's `hero.name` property value within the `<li>` element.
* The `[hero]` [*property binding*](guide/template-syntax#property-binding) passes the value of `selectedHero` from
the parent `HeroListComponent` to the `hero` property of the child `HeroDetailComponent`.
* The `(click)` [*event binding*](guide/user-input#click) calls the component's `selectHero` method when the user clicks a hero's name.
**Two-way data binding** is an important fourth form
that combines property and event binding in a single notation, using the `ngModel` directive.
Here's an example from the `HeroDetailComponent` template:
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
In two-way binding, a data property value flows to the input box from the component as with property binding.
The user's changes also flow back to the component, resetting the property to the latest value,
as with event binding.
Angular processes *all* data bindings once per JavaScript event cycle,
from the root of the application component tree through all child components.
<figure>
<img src="generated/images/guide/architecture/component-databinding.png" alt="Data Binding">
</figure>
Data binding plays an important role in communication between a template and its component.
<figure>
<img src="generated/images/guide/architecture/parent-child-binding.png" alt="Parent/Child binding">
</figure>
Data binding is also important for communication between parent and child components.
<hr/>
## Directives
<img src="generated/images/guide/architecture/directive.png" alt="Parent child" class="left">
Angular templates are *dynamic*. When Angular renders them, it transforms the DOM
according to the instructions given by **directives**.
A directive is a class with a `@Directive` decorator.
A component is a *directive-with-a-template*;
a `@Component` decorator is actually a `@Directive` decorator extended with template-oriented features.
<div class="l-sub-section">
While **a component is technically a directive**,
components are so distinctive and central to Angular applications that this architectural overview separates components from directives.
</div>
Two *other* kinds of directives exist: _structural_ and _attribute_ directives.
They tend to appear within an element tag as attributes do,
sometimes by name but more often as the target of an assignment or a binding.
**Structural** directives alter layout by adding, removing, and replacing elements in DOM.
The [example template](guide/architecture#templates) uses two built-in structural directives:
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" title="src/app/hero-list.component.html (structural)" region="structural"></code-example>
* [`*ngFor`](guide/displaying-data#ngFor) tells Angular to stamp out one `<li>` per hero in the `heroes` list.
* [`*ngIf`](guide/displaying-data#ngIf) includes the `HeroDetail` component only if a selected hero exists.
**Attribute** directives alter the appearance or behavior of an existing element.
In templates they look like regular HTML attributes, hence the name.
The `ngModel` directive, which implements two-way data binding, is
an example of an attribute directive. `ngModel` modifies the behavior of
an existing element (typically an `<input>`)
by setting its display value property and responding to change events.
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
Angular has a few more directives that either alter the layout structure
(for example, [ngSwitch](guide/template-syntax#ngSwitch))
or modify aspects of DOM elements and components
(for example, [ngStyle](guide/template-syntax#ngStyle) and [ngClass](guide/template-syntax#ngClass)).
Of course, you can also write your own directives. Components such as
`HeroListComponent` are one kind of custom directive.
<!-- PENDING: link to where to learn more about other kinds! -->
<hr/>
## Services
<img src="generated/images/guide/architecture/service.png" alt="Service" class="left">
_Service_ is a broad category encompassing any value, function, or feature that your application needs.
Almost anything can be a service.
A service is typically a class with a narrow, well-defined purpose. It should do something specific and do it well.
<br class="clear">
Examples include:
* logging service
* data service
* message bus
* tax calculator
* application configuration
There is nothing specifically _Angular_ about services. Angular has no definition of a service.
There is no service base class, and no place to register a service.
Yet services are fundamental to any Angular application. Components are big consumers of services.
Here's an example of a service class that logs to the browser console:
<code-example path="architecture/src/app/logger.service.ts" linenums="false" title="src/app/logger.service.ts (class)" region="class"></code-example>
Here's a `HeroService` that uses a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) to fetch heroes.
The `HeroService` depends on the `Logger` service and another `BackendService` that handles the server communication grunt work.
<code-example path="architecture/src/app/hero.service.ts" linenums="false" title="src/app/hero.service.ts (class)" region="class"></code-example>
Services are everywhere.
Component classes should be lean. They don't fetch data from the server,
validate user input, or log directly to the console.
They delegate such tasks to services.
A component's job is to enable the user experience and nothing more. It mediates between the view (rendered by the template)
and the application logic (which often includes some notion of a _model_).
A good component presents properties and methods for data binding.
It delegates everything nontrivial to services.
Angular doesn't *enforce* these principles.
It won't complain if you write a "kitchen sink" component with 3000 lines.
Angular does help you *follow* these principles by making it easy to factor your
application logic into services and make those services available to components through *dependency injection*.
<hr/>
## Dependency injection
<img src="generated/images/guide/architecture/dependency-injection.png" alt="Service" class="left">
_Dependency injection_ is a way to supply a new instance of a class
with the fully-formed dependencies it requires. Most dependencies are services.
Angular uses dependency injection to provide new components with the services they need.
<br class="clear">
Angular can tell which services a component needs by looking at the types of its constructor parameters.
For example, the constructor of your `HeroListComponent` needs a `HeroService`:
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (constructor)" region="ctor"></code-example>
When Angular creates a component, it first asks an **injector** for
the services that the component requires.
An injector maintains a container of service instances that it has previously created.
If a requested service instance is not in the container, the injector makes one and adds it to the container
before returning the service to Angular.
When all requested services have been resolved and returned,
Angular can call the component's constructor with those services as arguments.
This is *dependency injection*.
The process of `HeroService` injection looks a bit like this:
<figure>
<img src="generated/images/guide/architecture/injector-injects.png" alt="Service">
</figure>
If the injector doesn't have a `HeroService`, how does it know how to make one?
In brief, you must have previously registered a **provider** of the `HeroService` with the injector.
A provider is something that can create or return a service, typically the service class itself.
You can register providers in modules or in components.
In general, add providers to the [root module](guide/architecture#modules) so that
the same instance of a service is available everywhere.
<code-example path="architecture/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (module providers)" region="providers"></code-example>
Alternatively, register at a component level in the `providers` property of the `@Component` metadata:
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (component providers)" region="providers"></code-example>
Registering at a component level means you get a new instance of the
service with each new instance of that component.
<!-- We've vastly oversimplified dependency injection for this overview.
The full story is in the [dependency injection](guide/dependency-injection) page. -->
Points to remember about dependency injection:
* Dependency injection is wired into the Angular framework and used everywhere.
* The *injector* is the main mechanism.
* An injector maintains a *container* of service instances that it created.
* An injector can create a new service instance from a *provider*.
* A *provider* is a recipe for creating a service.
* Register *providers* with injectors.
<hr/>
## Wrap up
You've learned the basics about the eight main building blocks of an Angular application:
* [Modules](guide/architecture#modules)
* [Components](guide/architecture#components)
* [Templates](guide/architecture#templates)
* [Metadata](guide/architecture#metadata)
* [Data binding](guide/architecture#data-binding)
* [Directives](guide/architecture#directives)
* [Services](guide/architecture#services)
* [Dependency injection](guide/architecture#dependency-injection)
That's a foundation for everything else in an Angular application,
and it's more than enough to get going.
But it doesn't include everything you need to know.
Here is a brief, alphabetical list of other important Angular features and services.
Most of them are covered in this documentation (or soon will be).
> [**Animations**](guide/animations): Animate component behavior
without deep knowledge of animation techniques or CSS with Angular's animation library.
> **Change detection**: The change detection documentation will cover how Angular decides that a component property value has changed,
when to update the screen, and how it uses **zones** to intercept asynchronous activity and run its change detection strategies.
> **Events**: The events documentation will cover how to use components and services to raise events with mechanisms for
publishing and subscribing to events.
> [**Forms**](guide/forms): Support complex data entry scenarios with HTML-based validation and dirty checking.
> [**HTTP**](guide/http): Communicate with a server to get data, save data, and invoke server-side actions with an HTTP client.
> [**Lifecycle hooks**](guide/lifecycle-hooks): Tap into key moments in the lifetime of a component, from its creation to its destruction,
by implementing the lifecycle hook interfaces.
> [**Pipes**](guide/pipes): Use pipes in your templates to improve the user experience by transforming values for display. Consider this `currency` pipe expression:
>
> > `price | currency:'USD':true`
>
> It displays a price of 42.33 as `$42.33`.
> [**Router**](guide/router): Navigate from page to page within the client
application and never leave the browser.
> [**Testing**](guide/testing): Run unit tests on your application parts as they interact with the Angular framework
using the _Angular Testing Platform_.

View File

@ -11,18 +11,21 @@ of the code in this cookbook.
{@a app-wide-dependencies}
## Application-wide dependencies
Register providers for dependencies used throughout the application
in the `@Injectable()` decorator of the service itself.
Register providers for dependencies used throughout the application in the root application component, `AppComponent`.
The following example shows importing and registering
the `LoggerService`, `UserContext`, and the `UserService`
in the `@Component` metadata `providers` array.
<code-example path="dependency-injection-in-action/src/app/app.component.ts" region="import-services" title="src/app/app.component.ts (excerpt)" linenums="false">
<code-example path="dependency-injection/src/app/heroes/hero.service.3.ts" title="src/app/heroes/hero.service.3.ts" linenums="false">
</code-example>
`providedIn` here tells Angular that the root injector is responsible for creating an instance of the `HeroService`.
Services that are provided this way are automatically made available to the entire
application and don't need to be listed in any module.
Service classes can act as their own providers which is why defining them in the `@Injectable` decorator
All of these services are implemented as classes.
Service classes can act as their own providers which is why listing them in the `providers` array
is all the registration you need.
<div class="l-sub-section">
@ -37,21 +40,30 @@ guide.
</div>
Now that you've registered these services,
Angular can inject them into the constructor of *any* component or service, *anywhere* in the application.
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="ctor" title="src/app/hero-bios.component.ts (component constructor injection)" linenums="false">
</code-example>
<code-example path="dependency-injection-in-action/src/app/user-context.service.ts" region="ctor" title="src/app/user-context.service.ts (service constructor injection)" linenums="false">
</code-example>
{@a external-module-configuration}
## External module configuration
If a provider cannot be configured in the `@Injectable` decorator of the service, then register application-wide providers in the root `AppModule`, not in the `AppComponent`. Generally, register providers in the `NgModule` rather than in the root application component.
Generally, register providers in the `NgModule` rather than in the root application component.
Do this when users should explicitly opt-in to use a service, or the service should be
provided in a lazily-loaded context,
or when you are configuring another application global service _before the application starts_.
Do this when you expect the service to be injectable everywhere,
or you are configuring another application global service _before the application starts_.
Here is an example of the case where the component router configuration includes a non-default
Here is an example of the second case, where the component router configuration includes a non-default
[location strategy](guide/router#location-strategy) by listing its provider
in the `providers` list of the `AppModule`.
@ -127,7 +139,41 @@ Notice the `@Injectable()`decorator on the `UserContextService` class.
</code-example>
The `@Injectable` decorator indicates that the Angular DI system is used to create one or more instances of `UserContextService`.
That decorator makes it possible for Angular to identify the types of its two dependencies, `LoggerService` and `UserService`.
Technically, the `@Injectable()`decorator is only required for a service class that has _its own dependencies_.
The `LoggerService` doesn't depend on anything. The logger would work if you omitted `@Injectable()`
and the generated code would be slightly smaller.
But the service would break the moment you gave it a dependency and you'd have to go back
and add `@Injectable()` to fix it. Add `@Injectable()` from the start for the sake
of consistency and to avoid future pain.
<div class="alert is-helpful">
Although this site recommends applying `@Injectable()` to all service classes, don't feel bound by it.
Some developers prefer to add it only where needed and that's a reasonable policy too.
</div>
<div class="l-sub-section">
The `AppComponent` class had two dependencies as well but no `@Injectable()`.
It didn't need `@Injectable()` because that component class has the `@Component` decorator.
In Angular with TypeScript, a *single* decorator&mdash;*any* decorator&mdash;is sufficient to identify dependency types.
</div>
{@a service-scope}
@ -449,7 +495,7 @@ If the search is futile, the injector throws an error&mdash;unless the request w
A new injector has no providers.
Angular initializes the injectors it creates with some providers it cares about.
You have to register your _own_ application providers manually,
usually in the `@Injectable` decorator of the service, `providers` array of the `NgModule` or `Directive` metadata:
usually in the `providers` array of the `Component` or `Directive` metadata:
<code-example path="dependency-injection-in-action/src/app/app.component.ts" region="providers" title="src/app/app.component.ts (providers)">
@ -462,18 +508,15 @@ usually in the `@Injectable` decorator of the service, `providers` array of the
### Defining providers
The simple way of defining providers in the `@Injectable` decorator of the class is recommended.
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" title="src/app/heroes/hero.service.0.ts" linenums="false">
</code-example>
Another alternative is to mention the class in the providers array of the `@NgModule` and you're done.
The simple class provider is the most typical by far.
You mention the class in the `providers` array and you're done.
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="class-provider" title="src/app/hero-bios.component.ts (class provider)" linenums="false">
</code-example>
It's that simple because the most common injected service is an instance of a class.
But not every dependency can be satisfied by creating a new instance of a class.
You need other ways to deliver dependency values and that means you need other ways to specify a provider.

View File

@ -58,16 +58,16 @@ The [**Angular CLI**](https://cli.angular.io/) can generate a new `HeroService`
ng generate service heroes/hero
</code-example>
The command above creates the following `HeroService` skeleton.
That command creates the following `HeroService` skeleton.
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" title="src/app/heroes/hero.service.ts (CLI-generated)">
</code-example>
The `@Injectable` decorator is an essential ingredient in every Angular service definition.
Assume for now that the [`@Injectable` decorator](#injectable) is an essential ingredient in every Angular service definition.
The rest of the class has been rewritten to expose a `getHeroes` method
that returns the same mock data as before.
<code-example path="dependency-injection/src/app/heroes/hero.service.3.ts" title="src/app/heroes/hero.service.3.ts">
<code-example path="dependency-injection/src/app/heroes/hero.service.1.ts" title="src/app/heroes/hero.service.ts">
</code-example>
Of course, this isn't a real data service.
@ -81,9 +81,9 @@ _injecting the service_ into the `HeroList` component.
{@a injector-config}
{@a bootstrap}
## Injectors
## Register a service provider
A _service_ like `HeroService` is just a class in Angular until you register it with an Angular dependency injector.
A _service_ is just a class in Angular until you register it with an Angular dependency injector.
An Angular injector is responsible for creating service instances and injecting them into classes like the `HeroListComponent`.
@ -91,7 +91,8 @@ You rarely create an Angular injector yourself.
Angular creates injectors for you as it executes the app,
starting with the _root injector_ that it creates during the [bootstrap process](guide/bootstrapping).
Angular doesn't automatically know how you want to create instances of your services or the injector to create your service. You must configure it by specifying providers for every service.
You do have to register _providers_ with an injector
before the injector can create that service.
**Providers** tell the injector _how to create the service_.
Without a provider, the injector would not know
@ -101,30 +102,24 @@ nor be able to create the service.
<div class="l-sub-section">
You'll learn much more about _providers_ [below](#providers).
For now, it is sufficient to know that they configure where and how services are created.
For now it is sufficient to know that they create services
and must be registered with an injector.
</div>
There are many ways to register a service provider with an injector. This section shows the most common ways
of configuring a provider for your services.
You can register a provider with any Angular decorator that supports the **`providers` array property**.
{@a register-providers-injectable}
Many Angular decorators accept metadata with a `providers` property.
The two most important examples are `@Component` and `@NgModule`.
## @Injectable providers
{@a register-providers-component}
The `@Injectable` decorator identifies services and other classes that are intended to be injected. It can also be used to configure a provider for those services.
### _@Component_ providers
Here we configure a provider for `HeroService` using the `@Injectable` decorator on the class.
Here's a revised `HeroesComponent` that registers the `HeroService` in its `providers` array.
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" title="src/app/heroes/heroes.service.ts" linenums="false"> </code-example>
`providedIn` tells Angular that the root injector is responsible for creating an instance of the `HeroService` (by invoking its constructor) and making it available across the application. The CLI sets up this kind of a provider automatically for you when generating a new service.
Sometimes it's not desirable to have a service always be provided in the application root injector. Perhaps users should explicitly opt-in to using the service, or the service should be provided in a lazily-loaded context. In this case, the provider should be associated with a specific `@NgModule` class, and will be used by whichever injector includes that module.
In the following excerpt, the `@Injectable` decorator is used to configure a provider that will be available in any injector that includes the HeroModule.
<code-example path="dependency-injection/src/app/heroes/hero.service.4.ts" title="src/app/heroes/hero.service.ts" linenums="false"> </code-example>
<code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" title="src/app/heroes/heroes.component.ts" linenums="false">
</code-example>
{@a register-providers-ngmodule}
@ -138,7 +133,7 @@ In the following excerpt, the root `AppModule` registers two providers in its `p
The first entry registers the `UserService` class (_not shown_) under the `UserService` _injection token_.
The second registers a value (`HERO_DI_CONFIG`) under the `APP_CONFIG` _injection token_.
With the above registrations, Angular can inject the `UserService` or the `HERO_DI_CONFIG` value
Thanks to these registrations, Angular can inject the `UserService` or the `HERO_DI_CONFIG` value
into any class that it creates.
<div class="l-sub-section">
@ -146,25 +141,13 @@ into any class that it creates.
You'll learn about _injection tokens_ and _provider_ syntax [below](#providers).
</div>
{@a register-providers-component}
### _@Component_ providers
In addition to providing the service application-wide or within a particular `@NgModule`, services can also be provided in specific components. Services provided in component-level is only available within that component injector or in any of its child components.
The example below shows a revised `HeroesComponent` that registers the `HeroService` in its `providers` array.
<code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" title="src/app/heroes/heroes.component.ts" linenums="false">
</code-example>
{@a ngmodule-vs-comp}
### @Injectable, _@NgModule_ or _@Component_?
### _@NgModule_ or _@Component_?
Should you provide a service with an `@Injectable` decorator, in an `@NgModule`, or within an `@Component`?
The choices lead to differences in the final bundle size, service _scope_, and service _lifetime_.
When you register providers in the **@Injectable** decorator of the service itself, optimization tools such as those used by the CLI's production builds can perform tree shaking, which removes services that aren't used by your app. Tree shaking results in smaller bundle sizes.
Should you register a service with an Angular module or with a component?
The two choices lead to differences in service _scope_ and service _lifetime_.
**Angular module providers** (`@NgModule.providers`) are registered with the application's root injector.
Angular can inject the corresponding services in any class it creates.
@ -172,7 +155,7 @@ Once created, a service instance lives for the life of the app and Angular injec
You're likely to inject the `UserService` in many places throughout the app
and will want to inject the same service instance every time.
Providing the `UserService` with an Angular module is a good choice if an `@Injectable` provider is not an option..
Providing the `UserService` with an Angular module is a good choice.
<div class="l-sub-section">
@ -205,6 +188,189 @@ The scope and lifetime of component-provided services is a consequence of [the w
</div>
## Inject a service
The `HeroListComponent` should get heroes from the `HeroService`.
The component shouldn't create the `HeroService` with `new`.
It should ask for the `HeroService` to be injected.
You can tell Angular to inject a dependency in the component's constructor by specifying a **constructor parameter with the dependency type**.
Here's the `HeroListComponent` constructor, asking for the `HeroService` to be injected.
<code-example title="src/app/heroes/hero-list.component (constructor signature)" path="dependency-injection/src/app/heroes/hero-list.component.ts"
region="ctor-signature">
</code-example>
Of course, the `HeroListComponent` should do something with the injected `HeroService`.
Here's the revised component, making use of the injected service, side-by-side with the previous version for comparison.
<code-tabs>
<code-pane title="hero-list.component (with DI)" path="dependency-injection/src/app/heroes/hero-list.component.2.ts">
</code-pane>
<code-pane title="hero-list.component (without DI)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts">
</code-pane>
</code-tabs>
Notice that the `HeroListComponent` doesn't know where the `HeroService` comes from.
_You_ know that it comes from the parent `HeroesComponent`.
But if you decided instead to provide the `HeroService` in the `AppModule`,
the `HeroListComponent` wouldn't change at all.
The _only thing that matters_ is that the `HeroService` is provided in some parent injector.
{@a singleton-services}
## Singleton services
Services are singletons _within the scope of an injector_.
There is at most one instance of a service in a given injector.
There is only one root injector and the `UserService` is registered with that injector.
Therefore, there can be just one `UserService` instance in the entire app
and every class that injects `UserService` get this service instance.
However, Angular DI is a
[hierarchical injection system](guide/hierarchical-dependency-injection),
which means that nested injectors can create their own service instances.
Angular creates nested injectors all the time.
{@a component-child-injectors}
## Component child injectors
For example, when Angular creates a new instance of a component that has `@Component.providers`,
it also creates a new _child injector_ for that instance.
Component injectors are independent of each other and
each of them creates its own instances of the component-provided services.
When Angular destroys one of these component instance, it also destroys the
component's injector and that injector's service instances.
Thanks to [injector inheritance](guide/hierarchical-dependency-injection),
you can still inject application-wide services into these components.
A component's injector is a child of its parent component's injector,
and a descendent of its parent's parent's injector, and so on all the way back to the application's _root_ injector.
Angular can inject a service provided by any injector in that lineage.
For example, Angular could inject a `HeroListComponent`
with both the `HeroService` provided in `HeroComponent`
and the `UserService` provided in `AppModule`.
{@a testing-the-component}
## Testing the component
Earlier you saw that designing a class for dependency injection makes the class easier to test.
Listing dependencies as constructor parameters may be all you need to test application parts effectively.
For example, you can create a new `HeroListComponent` with a mock service that you can manipulate
under test:
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" title="src/app/test.component.ts" linenums="false">
</code-example>
<div class="l-sub-section">
Learn more in the [Testing](guide/testing) guide.
</div>
{@a service-needs-service}
## When the service needs a service
The `HeroService` is very simple. It doesn't have any dependencies of its own.
What if it had a dependency? What if it reported its activities through a logging service?
You'd apply the same *constructor injection* pattern,
adding a constructor that takes a `Logger` parameter.
Here is the revised `HeroService` that injects the `Logger`, side-by-side with the previous service for comparison.
<code-tabs>
<code-pane title="src/app/heroes/hero.service (v2)" path="dependency-injection/src/app/heroes/hero.service.2.ts">
</code-pane>
<code-pane title="src/app/heroes/hero.service (v1)" path="dependency-injection/src/app/heroes/hero.service.1.ts">
</code-pane>
</code-tabs>
The constructor asks for an injected instance of a `Logger` and stores it in a private field called `logger`.
The `getHeroes()` method logs a message when asked to fetch heroes.
{@a logger-service}
#### The dependent _Logger_ service
The sample app's `Logger` service is quite simple:
<code-example path="dependency-injection/src/app/logger.service.ts" title="src/app/logger.service.ts">
</code-example>
If the app didn't provide this `Logger`,
Angular would throw an exception when it looked for a `Logger` to inject
into the `HeroService`.
<code-example language="sh" class="code-shell">
ERROR Error: No provider for Logger!
</code-example>
Because a singleton logger service is useful everywhere,
it's provided in the root `AppModule`.
<code-example path="dependency-injection/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers-2">
</code-example>
{@a injectable}
## _@Injectable()_
The **[@Injectable()](api/core/Injectable)** decorator identifies a service class
that _might_ require injected dependencies.
The `HeroService` must be annotated with `@Injectable()` because it requires an injected `Logger`.
<div class="alert is-important">
Always write `@Injectable()` with parentheses, not just `@Injectable`.
</div>
When Angular creates a class whose constructor has parameters,
it looks for type and injection metadata about those parameters
so that it can inject the right service.
If Angular can't find that parameter information, it throws an error.
Angular can only find the parameter information _if the class has a decorator of some kind_.
While _any_ decorator will do,
the `@Injectable()` decorator is the standard decorator for service classes.
<div class="l-sub-section">
The decorator requirement is imposed by TypeScript.
TypeScript normally discards parameter type information when it _transpiles_ the code to JavaScript.
It preserves this information if the class has a decorator
and the `emitDecoratorMetadata` compiler option is set `true`
in TypeScript's `tsconfig.json` configuration file, .
The CLI configures `tsconfig.json` with `emitDecoratorMetadata: true`
It's your job to put `@Injectable()` on your service classes.
</div>
The `Logger` service is annotated with `@Injectable()` decorator too,
although it has no constructor and no dependencies.
In fact, _every_ Angular service class in this app is annotated with the `@Injectable()` decorator, whether or not it has a constructor and dependencies.
`@Injectable()` is a required coding style for services.
{@a providers}
@ -218,6 +384,8 @@ You must register a service *provider* with an injector, or it won't know how to
The next few sections explain the many ways you can specify a provider.
Almost all of the accompanying code snippets are extracts from the sample app's `providers.component.ts` file.
### The class as its own provider
There are many ways to *provide* something that looks and behaves like a `Logger`.
@ -404,185 +572,6 @@ Here you see the new and the old implementation side-by-side:
</code-tabs>
{@a tree-shakable-provider}
### Tree-shakable providers
Tree shaking is the ability to remove code that is not referenced in an application from the final bundle. Tree-shakable providers give Angular the ability to remove services that are not used in your application from the final output. This significantly reduces the size of your bundles.
Ideally, if an application is not injecting a service, it should not be included in the final output. However, it turns out that the Angular compiler cannot identify at build time if the service will be required or not. Because it's always possible to inject a service directly using `injector.get(Service)`, Angular cannot identify all of the places in your code where this injection could happen, so it has no choice but to include the service in the injector regardless. Thus, services provided in modules are not tree-shakeable.
Let us consider an example of non-tree-shakable providers in Angular.
In this example, to provide services in Angular, you include them in an `@NgModule`:
<code-example path="dependency-injection/src/app/tree-shaking/service-and-module.ts" title="src/app/tree-shaking/service-and-modules.ts" linenums="false"> </code-example>
This module can then be imported into your application module, to make the service available for injection in your app:
<code-example path="dependency-injection/src/app/tree-shaking/app.module.ts" title="src/app/tree-shaking/app.modules.ts" linenums="false"> </code-example>
When `ngc` runs, it compiles AppModule into a module factory, which contains definitions for all the providers declared in all the modules it includes. At runtime, this factory becomes an injector that instantiates these services.
Tree-shaking doesn't work in the method above because Angular cannot decide to exclude one chunk of code (the provider definition for the service within the module factory) based on whether another chunk of code (the service class) is used. To make services tree-shakeable, the information about how to construct an instance of the service (the provider definition) needs to be a part of the service class itself.
#### Creating tree-shakable providers
To create providers that are tree-shakable, the information that used to be specified in the module should be specified in the `@Injectable` decorator on the service itself.
The following example shows the tree-shakeable equivalent to the `ServiceModule` example above:
<code-example path="dependency-injection/src/app/tree-shaking/service.ts" title="src/app/tree-shaking/service.ts" linenums="false"> </code-example>
In the example above, `providedIn` allows you to declare the injector which injects this service. Unless there is a special case, the value should always be root. Setting the value to root ensures that the service is scoped to the root injector, without naming a particular module that is present in that injector.
The service can be instantiated by configuring a factory function as shown below:
<code-example path="dependency-injection/src/app/tree-shaking/service.0.ts" title="src/app/tree-shaking/service.0.ts" linenums="false"> </code-example>
{@a injector-config}
{@a bootstrap}
## Inject a service
The `HeroListComponent` should get heroes from the `HeroService`.
The component shouldn't create the `HeroService` with `new`.
It should ask for the `HeroService` to be injected.
You can tell Angular to inject a dependency in the component's constructor by specifying a **constructor parameter with the dependency type**.
Here's the `HeroListComponent` constructor, asking for the `HeroService` to be injected.
<code-example title="src/app/heroes/hero-list.component (constructor signature)" path="dependency-injection/src/app/heroes/hero-list.component.ts"
region="ctor-signature">
</code-example>
Of course, the `HeroListComponent` should do something with the injected `HeroService`.
Here's the revised component, making use of the injected service, side-by-side with the previous version for comparison.
<code-tabs>
<code-pane title="hero-list.component (with DI)" path="dependency-injection/src/app/heroes/hero-list.component.2.ts">
</code-pane>
<code-pane title="hero-list.component (without DI)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts">
</code-pane>
</code-tabs>
Notice that the `HeroListComponent` doesn't know where the `HeroService` comes from.
_You_ know that it comes from the parent `HeroesComponent`.
If you decided instead to provide the `HeroService` in the `AppModule`,
the `HeroListComponent` wouldn't change at all.
The _only thing that matters_ is that the `HeroService` is provided in some parent injector.
{@a singleton-services}
## Singleton services
Services are singletons _within the scope of an injector_.
There is at most one instance of a service in a given injector.
There is only one root injector, and the `UserService` is registered with that injector.
Therefore, there can be just one `UserService` instance in the entire app,
and every class that injects `UserService` get this service instance.
However, Angular DI is a
[hierarchical injection system](guide/hierarchical-dependency-injection),
which means that nested injectors can create their own service instances.
Angular creates nested injectors all the time.
{@a component-child-injectors}
## Component child injectors
Component injectors are independent of each other and
each of them creates its own instances of the component-provided services.
For example, when Angular creates a new instance of a component that has `@Component.providers`,
it also creates a new _child injector_ for that instance.
When Angular destroys one of these component instances, it also destroys the
component's injector and that injector's service instances.
Because of [injector inheritance](guide/hierarchical-dependency-injection),
you can still inject application-wide services into these components.
A component's injector is a child of its parent component's injector,
and a descendent of its parent's parent's injector, and so on all the way back to the application's _root_ injector.
Angular can inject a service provided by any injector in that lineage.
For example, Angular could inject a `HeroListComponent`
with both the `HeroService` provided in `HeroComponent`
and the `UserService` provided in `AppModule`.
{@a testing-the-component}
## Testing the component
Earlier you saw that designing a class for dependency injection makes the class easier to test.
Listing dependencies as constructor parameters may be all you need to test application parts effectively.
For example, you can create a new `HeroListComponent` with a mock service that you can manipulate
under test:
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" title="src/app/test.component.ts" linenums="false">
</code-example>
<div class="l-sub-section">
Learn more in the [Testing](guide/testing) guide.
</div>
{@a service-needs-service}
## When the service needs a service
The `HeroService` is very simple. It doesn't have any dependencies of its own.
What if it had a dependency? What if it reported its activities through a logging service?
You'd apply the same *constructor injection* pattern,
adding a constructor that takes a `Logger` parameter.
Here is the revised `HeroService` that injects the `Logger`, side-by-side with the previous service for comparison.
<code-tabs>
<code-pane title="src/app/heroes/hero.service (v2)" path="dependency-injection/src/app/heroes/hero.service.2.ts">
</code-pane>
<code-pane title="src/app/heroes/hero.service (v1)" path="dependency-injection/src/app/heroes/hero.service.1.ts">
</code-pane>
</code-tabs>
The constructor asks for an injected instance of a `Logger` and stores it in a private field called `logger`.
The `getHeroes()` method logs a message when asked to fetch heroes.
{@a logger-service}
#### The dependent _Logger_ service
The sample app's `Logger` service is quite simple:
<code-example path="dependency-injection/src/app/logger.service.ts" title="src/app/logger.service.ts">
</code-example>
If the app didn't provide this `Logger`,
Angular would throw an exception when it looked for a `Logger` to inject
into the `HeroService`.
<code-example language="sh" class="code-shell">
ERROR Error: No provider for Logger!
</code-example>
Because a singleton logger service is useful everywhere,
it's provided in the root `AppModule`.
<code-example path="dependency-injection/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers-2">
</code-example>
{@a token}
## Dependency injection tokens
@ -652,7 +641,6 @@ There is no interface type information left for Angular to find at runtime.
</div>
{@a injection-token}
### _InjectionToken_
@ -661,45 +649,52 @@ One solution to choosing a provider token for non-class dependencies is
to define and use an [*InjectionToken*](api/core/InjectionToken).
The definition of such a token looks like this:
<code-example>
import { InjectionToken } from '@angular/core';
export const TOKEN = new InjectionToken('desc');
<code-example path="dependency-injection/src/app/app.config.ts" region="token" title="src/app/app.config.ts" linenums="false">
</code-example>
You can directly configure a provider when creating an `InjectionToken`. The provider configuration determines which injector provides the token and how the value will be created. This is similar to using `@Injectable`, except that you cannot define standard providers (such as `useClass` or `useFactory`) with `InjectionToken`. Instead, you specify a factory function which returns the value to be provided directly.
The type parameter, while optional, conveys the dependency's type to developers and tooling.
The token description is another developer aid.
<code-example>
export const TOKEN =
new InjectionToken('desc', { providedIn: 'root', factory: () => new AppConfig(), })
Register the dependency provider using the `InjectionToken` object:
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9" linenums="false">
</code-example>
Now you can inject the configuration object into any constructor that needs it, with
the help of an `@Inject` decorator:
<code-example>
constructor(@Inject(TOKEN));
<code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" title="src/app/app.component.ts" linenums="false">
</code-example>
If the factory function needs access to other DI tokens, it can use the inject function from `@angular/core` to request dependencies.
<div class="l-sub-section">
<code-example>
const TOKEN =
new InjectionToken('tree-shakeable token',
{ providedIn: 'root', factory: () =>
new AppConfig(inject(Parameter1), inject(Paremeter2)), });
</code-example>
Although the `AppConfig` interface plays no role in dependency injection,
it supports typing of the configuration object within the class.
</div>
Alternatively, you can provide and inject the configuration object in an ngModule like `AppModule`.
<code-example path="dependency-injection/src/app/app.module.ts" region="providers" title="src/app/app.module.ts (providers)"></code-example>
{@a optional}
## Optional dependencies
You can tell Angular that the dependency is optional by annotating the constructor argument with null:
The `HeroService` *requires* a `Logger`, but what if it could get by without
a `logger`?
You can tell Angular that the dependency is optional by annotating the
constructor argument with `@Optional()`:
<code-example>
constructor(@Inject(Token, null));
<code-example path="dependency-injection/src/app/providers.component.ts" region="import-optional">
</code-example>
When using optional dependencies, your code must be prepared for a null value.
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-10-ctor" linenums="false">
</code-example>
When using `@Optional()`, your code must be prepared for a null value. If you
don't register a `logger` somewhere up the line, the injector will set the
value of `logger` to null.
## Summary

View File

@ -740,7 +740,7 @@ Adding `<live-example></live-example>` to the page generates the two default lin
2. a link that downloads that sample.
Clicking the first link opens the code sample on StackBlitz in a new browser tab.
Clicking the first link opens the code sample in a new browser tab in the "embedded Stackblitz" style.
You can change the appearance and behavior of the live example with attributes and classes.
@ -810,13 +810,16 @@ You can embed the Stackblitz within the guide page itself by adding the `embedde
For performance reasons, the Stackblitz does not start right away. The reader sees an image instead. Clicking the image starts the sometimes-slow process of launching the embedded Stackblitz within an iframe on the page.
Here's an embedded live example for this guide.
You usually replace the default Stackblitz image with a custom image that better represents the sample.
Store that image in the `content/images` directory in a folder with a name matching the corresponding example folder.
Here's an embedded live example for this guide. It has a custom image created from a snapshot of the running app, overlayed with `content/images/Stackblitz/unused/click-to-run.png`.
```html
<live-example embedded></live-example>
<live-example embedded img="guide/docs-style-guide/docs-style-guide-Stackblitz.png"></live-example>
```
<live-example embedded></live-example>
<live-example embedded img="guide/docs-style-guide/docs-style-guide-Stackblitz.png"></live-example>
{@a anchors}

View File

@ -1,157 +0,0 @@
# Angular Elements Overview
[Custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) are a Web Platform feature currently supported by Chrome, Opera, and Safari, and available in other browsers through polyfills (see [Browser Support](#browser-support)).
A custom element extends HTML by allowing you to define a tag whose content is created and controlled by JavaScript code.
The browser maintains a `CustomElementRegistry` of defined custom elements (also called Web Components), which maps an instantiable JavaScript class to an HTML tag.
The `@angular/elements` package exports a `createCustomElement()` API that provides a bridge from Angular's component interface and change detection functionality to the built-in DOM API.
Transforming a component to a custom element makes all of the required Angular infrastructure available to the browser. Creating a custom element is simple and straightforward, and automatically connects your component-defined view with change detection and data binding, mapping Angular functionality to the corresponding native HTML equivalents.
## Using custom elements
Custom elements bootstrap themselves - they start automatically when they are added to the DOM, and are automatically destroyed when removed from the DOM. Once a custom element is added to the DOM for any page, it looks and behaves like any other HTML element, and does not require any special knowledge of Angular terms or usage conventions.
- <b>Easy dynamic content in an Angular app</b>
Transforming a component to a custom element provides an easy path to creating dynamic HTML content in your Angular app. HTML content that you add directly to the DOM in an Angular app is normally displayed without Angular processing, unless you define a _dynamic component_, adding your own code to connect the HTML tag to your app data, and participate in change detection. With a custom element, all of that wiring is taken care of automatically.
- <b>Content-rich applications</b>
If you have a content-rich app, such as the Angular app that presents this documentation, custom elements let you give your content providers sophisticated Angular functionality without requiring knowledge of Angular. For example, an Angular guide like this one is added directly to the DOM by the Angular navigation tools, but can include special elements like `<code-snippet>` that perform complex operations. All you need to tell your content provider is the syntax of your custom element. They don't need to know anything about Angular, or anything about your component's data structures or implementation.
### How it works
Use the `createCustomElement()` function to convert a component into a class that can be registered with the browser as a custom element.
After you register your configured class with the browser's custom-element registry, you can use the new element just like a built-in HTML element in content that you add directly into the DOM:
```
<my-popup message="Use Angular!"></my-popup>
```
When your custom element is placed on a page, the browser creates an instance of the registered class and adds it to the DOM. The content is provided by the component's template, which uses Angular template syntax, and is rendered using the component and DOM data. Input properties in the component correspond to input attributes for the element.
<figure>
<img src="generated/images/guide/elements/customElement1.png" alt="Custom element in browser" class="left">
</figure>
<hr class="clear">
<div class="l-sub-section">
We are working on custom elements that can be used by web apps built on other frameworks.
A minimal, self-contained version of the Angular framework will be injected as a service to support the component's change-detection and data-binding functionality.
For more about the direction of development, check out this [video presentation](https://www.youtube.com/watch?v=vHI5C-9vH-E).
</div>
## Transforming components to custom elements
Angular provides the `createCustomElement()` function for converting an Angular component,
together with its dependencies, to a custom element. The function collects the component's
observable properties, along with the Angular functionality the browser needs to
create and destroy instances, and to detect and respond to changes.
The conversion process implements the `NgElementConstructor` interface, and creates a
constructor class that is configured to produce a self-bootstrapping instance of your component.
Use a JavaScript function, `customElements.define()`, to register the configured constructor
and its associated custom-element tag with the browser's `CustomElementRegistry`.
When the browser encounters the tag for the registered element, it uses the constructor to create a custom-element instance.
<figure>
<img src="generated/images/guide/elements/createElement.png" alt="Transform a component to a custom element" class="left">
</figure>
### Mapping
A custom element _hosts_ an Angular component, providing a bridge between the data and logic defined in the component and standard DOM APIs. Component properties and logic maps directly into HTML attributes and the browser's event system.
- The creation API parses the component looking for input properties, and defines corresponding attributes for the custom element. It transforms the property names to make them compatible with custom elements, which do not recognize case distinctions. The resulting attribute names use dash-separated lowercase. For example, for a component with `@Input('myInputProp') inputProp`, the corresponding custom element defines an attribute `my-input-prop`.
- Component outputs are dispatched as HTML [Custom Events](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent), with the name of the custom event matching the output name. For example, for a component with `@Output() valueChanged = new EventEmitter()`, the corresponding custom element will dispatch events with the name "valueChanged", and the emitted data will be stored on the events `detail` property. If you provide an alias, that value is used; for example, `@Output('myClick') clicks = new EventEmitter<string>();` results in dispatch events with the name "myClick".
For more information, see Web Component documentation for [Creating custom events](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events#Creating_custom_events).
{@a browser-support}
## Browser support for custom elements
The recently-developed [custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) Web Platform feature is currently supported natively in a number of browsers. Support is pending or planned in other browsers.
<table>
<tr>
<th>Browser</th>
<th>Custom Element Support</th>
</tr>
<tr>
<td>Chrome</td>
<td>Supported natively.</td>
</tr>
<tr>
<td>Opera</td>
<td>Supported natively.</td>
</tr>
<tr>
<td>Safari</td>
<td>Supported natively.</td>
</tr>
<tr>
<td>Firefox</td>
<td> Set the <code>dom.webcomponents.enabled</code> and <code>dom.webcomponents.customelements.enabled</code> preferences to true. Planned to be enabled by default in version 60/61.</td>
</tr>
<tr>
<td>Edge</td>
<td>Working on an implementation. <br>
</td>
</tr>
</table>
In browsers that support Custom Elements natively, the specification requires developers use ES2015 classes to define Custom Elements - developers can opt-in to this by setting the `target: "es2015"` property in their project's `tsconfig.json`. As Custom Element and ES2015 support may not be available in all browsers, developers can instead choose to use a polyfill to support older browsers and ES5 code.
Use the [Angular CLI](https://cli.angular.io/) to automatically set up your project with the correct polyfill: `ng add @angular/elements --name=*your_project_name*`.
- For more information about polyfills, see [polyfill documentation](https://www.webcomponents.org/polyfills).
- For more information about Angular browser support, see [Browser Support](guide/browser-support).
## Example: A Popup Service
Previously, when you wanted to add a component to an app at runtime, you had to define a _dynamic component_. The app module would have to list your dynamic component under `entryComponents`, so that the app wouldn't expect it to be present at startup, and then you would have to load it, attach it to an element in the DOM, and wire up all of the dependencies, change detection, and event handling, as described in [Dynamic Component Loader](guide/dynamic-component-loader).
Using an Angular custom element makes the process much simpler and more transparent, by providing all of the infrastructure and framework automatically&mdash;all you have to do is define the kind of event handling you want. (You do still have to exclude the component from compilation, if you are not going to use it in your app.)
The Popup Service example app defines a component that you can either load dynamically or convert to a custom element.
- `popup.component.ts` defines a simple pop-up element that displays an input message, with some animation and styling.
- `popup.service.ts` creates an injectable service that provides two different ways to invoke the PopupComponent; as a dynamic component, or as a custom element. Notice how much more setup is required for the dynamic-loading method.
- `app.module.ts` adds the PopupComponent in the module's `entryComponents` list, to exclude it from compilation and avoid startup warnings or errors.
- `app.component.ts` defines the app's root component, which uses the PopupService to add the pop-up to the DOM at run time. When the app runs, the root component's constructor converts PopupComponent to a custom element.
For comparison, the demo shows both methods. One button adds the popup using the dynamic-loading method, and the other uses the custom element. You can see that the result is the same; only the preparation is different.
<code-tabs>
<code-pane title="popup.component.ts" path="elements/src/app/popup.component.ts">
</code-pane>
<code-pane title="popup.service.ts" path="elements/src/app/popup.service.ts">
</code-pane>
<code-pane title="app.module.ts" path="elements/src/app/app.module.ts">
</code-pane>
<code-pane title="app.component.ts" path="elements/src/app/app.component.ts">
</code-pane>
</code-tabs>

View File

@ -19,11 +19,12 @@ unexpected definitions.
## Ahead-of-time (AOT) compilation
You can compile Angular applications at build time.
You can compile Angular applications at build time.
By compiling your application using the compiler-cli, `ngc`, you can bootstrap directly to a module factory, meaning you don't need to include the Angular compiler in your JavaScript bundle.
Ahead-of-time compiled applications also benefit from decreased load time and increased performance.
## Annotation
In practice, a synonym for [Decoration](guide/glossary#decorator).
@ -51,7 +52,7 @@ Learn about them in the [_Attribute Directives_](guide/attribute-directives) gui
## Barrel
A way to *roll up exports* from several ES2015 modules into a single convenient ES2015 module.
The barrel itself is an ES2015 module file that re-exports selected exports of other ES2015 modules.
The barrel itself is an ES2015 module file that re-exports *selected* exports of other ES2015 modules.
For example, imagine three ES2015 modules in a `heroes` folder:
@ -66,6 +67,8 @@ For example, imagine three ES2015 modules in a `heroes` folder:
export class HeroService {}
</code-example>
Without a barrel, a consumer needs three import statements:
<code-example>
@ -93,14 +96,20 @@ Now a consumer can import what it needs from the barrel.
</code-example>
The Angular [scoped packages](guide/glossary#scoped-package) each have a barrel named `index`.
<div class="alert is-important">
You can often achieve the same result using [NgModules](guide/glossary#ngmodule) instead.
</div>
## Binding
Usually refers to [data binding](guide/glossary#data-binding) and the act of
@ -112,6 +121,7 @@ between a "token"&mdash;also referred to as a "key"&mdash;and a dependency [prov
## Bootstrap
You launch an Angular application by "bootstrapping" it using the application root NgModule (`AppModule`).
Bootstrapping identifies an application's top level "root" [component](guide/glossary#component),
@ -122,21 +132,15 @@ You can bootstrap multiple apps in the same `index.html`, each app with its own
{@a C}
## camelCase
{@a dash-case}
The practice of writing compound words or phrases such that each word or abbreviation begins with a capital letter
_except the first letter, which is lowercase_.
{@a camelcase}
Function, property, and method names are typically spelled in camelCase. For example, `square`, `firstName`, and `getHeroes`. Notice that `square` is an example of how you write a single word in camelCase.
## Case conventions
Angular uses capitalization conventions to distinguish the names of various types, as described in the [Style Guide "Naming" section](guide/styleguide#02-01).
- camelCase : symbols, properties, methods, pipe names, interfaces, non-component directive selectors, constants
- UpperCamelCase (also called PascalCase): Class names
- dash-case (also called "kebab-case"): descriptive part of file names, component selectors
- underscore_case (or "snake_case"): not typically used in Angular
- UPPER_SNAKE_CASE : traditional for constants (acceptable, but prefer camelCase)
camelCase is also known as *lower camel case* to distinguish it from *upper camel case*, or [PascalCase](guide/glossary#pascalcase).
In Angular documentation, "camelCase" always means *lower camel case*.
## CLI
@ -147,6 +151,7 @@ Learn more in the [Getting Started](guide/quickstart) guide.
{@a component}
## Component
An Angular class responsible for exposing data to a [view](guide/glossary#view) and handling most of the views display and user-interaction logic.
@ -162,25 +167,22 @@ as a view.
Those familiar with "MVC" and "MVVM" patterns will recognize
the component in the role of "controller" or "view model".
{@a custom-element}
## Custom element
A Web Platform feature, currently supported by most browsers, and available in other browsers through polyfills (see [Browser Support](guide/browser-support)).
The custom element feature extends HTML by allowing you to define a tag whose content is created and controlled by JavaScript code. A custom element (also called a *web component*) is recognized by a browser when it is added to the [CustomElementRegistry](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry).
You can use the API to transform an Angular component so that it can be registered with the browser and used in any HTML that you add directly to the DOM within an Angular app. The custom element tag inserts the component's view, with change-detection and data-binding functionality, into content that would otherwise be displayed without Angular processing.
See also [Dynamic components](guide/glossary#dynamic-components).
{@a D}
## dash-case
The practice of writing compound words or phrases such that each word is separated by a dash or hyphen (`-`).
This form is also known as kebab-case.
[Directive](guide/glossary#directive) selectors (like `my-app`) and
the root of filenames (such as `hero-list.component.ts`) are often
spelled in dash-case.
## Data binding
Data binding allow apps to display data values to a user and respond to user
Applications display data values to a user and respond to user
actions (such as clicks, touches, and keystrokes).
In data binding, you declare the relationship between an HTML widget and data source
@ -213,7 +215,7 @@ operations and supporting declaration syntax.
A *function* that adds metadata to a class, its members (properties, methods) and function arguments.
Decorators (also called annotations) are an experimental (stage 2), JavaScript language [feature](https://github.com/wycats/javascript-decorators). TypeScript adds support for decorators.
Decorators are an experimental (stage 2), JavaScript language [feature](https://github.com/wycats/javascript-decorators). TypeScript adds support for decorators.
To apply a decorator, position it immediately above or to the left of the item it decorates.
@ -221,7 +223,6 @@ Angular has its own set of decorators to help it interoperate with your applicat
The following example is a `@Component` decorator that identifies a
class as an Angular [component](guide/glossary#component) and an `@Input` decorator applied to the `name` property
of that component. The elided object argument to the `@Component` decorator would contain the pertinent component metadata.
```
@Component({...})
export class AppComponent {
@ -229,7 +230,6 @@ export class AppComponent {
@Input() name:string;
}
```
The scope of a decorator is limited to the language feature
that it decorates. None of the decorations shown here will "leak" to other
classes that follow it in the file.
@ -334,34 +334,39 @@ as HTML attributes, hence the name.
shaping or reshaping HTML layout, typically by adding, removing, or manipulating
elements and their children.
{@a dynamic-components}
## Dynamic component loading
A technique for adding a component to the DOM at run time, which requires that you exclude the component from compilation, then connect it to Angular's change-detection and event handling framework when you add it to the DOM.
See also [Custom element](guide/glossary#custom-element), which provides an easier path with the same result.
{@a E}
{@a ecma}
## ECMAScript
The [official JavaScript language specification](https://en.wikipedia.org/wiki/ECMAScript).
Not all browsers support the latest ECMAScript standard, but you can use transpilers (like [TypeScript](guide/glossary#typescript)) to write code using the latest features, which will then be transpiled to code that runs on versions that are supported by browsers.
The latest approved version of JavaScript is
[ECMAScript 2017](http://www.ecma-international.org/ecma-262/8.0/)
(also known as "ES2017" or "ES8"). Many Angular developers write their applications
in ES8 or a dialect that strives to be
compatible with it, such as [TypeScript](guide/glossary#typescript).
Most modern browsers only support the much older "ECMAScript 5" (also known as "ES5") standard.
Applications written in ES2017, ES2016, ES2015, or one of their dialects must be [transpiled](guide/glossary#transpile)
to ES5 JavaScript.
Angular developers can write in ES5 directly.
{@a element}
## ES2015
## Element
Short hand for [ECMAScript](guide/glossary#ecmascript) 2015.
Angular defines an `ElementRef` class to wrap render-specific native UI elements. This allows you use Angular templates and data-binding to access DOM elements without reference to the native element in most cases.
The documentation generally refers to either elements (`ElementRef` instances) or DOM elements (which could be accessed directly if necessary).
## ES5
Compare [Custom element](guide/glossary#custom-element).
Short hand for [ECMAScript](guide/glossary#ecmascript) 5, the version of JavaScript run by most modern browsers.
## ES6
Short hand for [ECMAScript](guide/glossary#ecmascript) 2015.
{@a F}
@ -378,7 +383,7 @@ Compare [Custom element](guide/glossary#custom-element).
An object in the Angular [dependency-injection system](guide/glossary#dependency-injection)
that can find a named dependency in its cache or create a dependency
with a registered [provider](guide/glossary#provider). Injectors are created for NgModules automatically as part of the bootstrap process, and inherited through the component hierarchy.
with a registered [provider](guide/glossary#provider).
## Input
@ -406,17 +411,13 @@ or displayed between element tags, as in this example.
</code-example>
Read more about [interpolation](guide/template-syntax#interpolation) in the
[Template Syntax](guide/template-syntax) page.
{@a J}
## JavaScript
See [ECMAScript](guide/glossary#ecma), [TypeScript](guide/glossary#typescript).
{@a jit}
@ -429,6 +430,10 @@ Consider using the [ahead-of-time](guide/glossary#aot) mode for production apps.
{@a K}
## kebab-case
See [dash-case](guide/glossary#dash-case).
{@a L}
@ -472,8 +477,11 @@ For details and examples, see the [NgModules](guide/ngmodules) page.
For a comparison, see [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
</div>
A cohesive block of code dedicated to a single purpose.
Angular apps are modular.
@ -514,19 +522,18 @@ For details and examples, see [NgModules](guide/ngmodules) and the
related files in that section.
{@a O}
## Observable
An subscribable message publisher, which provides multiple items that arrive asynchronously over time.
An array whose items arrive asynchronously over time.
Observables help you manage asynchronous data, such as data coming from a backend service.
Observables are used within Angular itself, including Angular's event system and its HTTP client service.
To use observables, Angular uses a third-party library called Reactive Extensions (RxJS).
Observables are a proposed feature for ES2016, the next version of JavaScript.
Currently, Angular depends on a third-party library called Reactive Extensions (RxJS) to provide observables.
For more information, see the [Observables guide](guide/observables).
## Output
@ -542,6 +549,15 @@ See the [Input and output properties](guide/template-syntax#inputs-outputs) sect
{@a P}
## PascalCase
The practice of writing individual words, compound words, or phrases such that each word or abbreviation begins with a capital letter.
Class names are typically spelled in PascalCase. For example, `Person` and `HeroDetailComponent`.
This form is also known as *upper camel case* to distinguish it from *lower camel case* or simply [camelCase](guide/glossary#camelcase).
In this documentation, "PascalCase" means *upper camel case* and "camelCase" means *lower camel case*.
## Pipe
An Angular pipe is a function that transforms input values to output values for
@ -660,6 +676,15 @@ Applications often require services such as a data service or a logging service.
For more information, see the [Services](tutorial/toh-pt4) page of the [Tour of Heroes](tutorial) tutorial.
{@a snake-case}
## snake_case
The practice of writing compound words or phrases such that an
underscore (`_`) separates one word from the next. This form is also known as *underscore case*.
{@a structural-directive}
@ -715,22 +740,23 @@ of the [Template Syntax](guide/template-syntax) page.
## Transpile
The process of transforming code written in one form of JavaScript
(such as TypeScript) into another form of JavaScript. (See also [ECMAScript](guide/glossary#ecma)).
{@a typescript}
(such as TypeScript) into another form of JavaScript (such as [ES5](guide/glossary#es5)).
## TypeScript
A version of JavaScript that supports most [ECMAScript 2015](guide/glossary#ecma)
A version of JavaScript that supports most [ECMAScript 2015](guide/glossary#es2015)
language features such as [decorators](guide/glossary#decorator).
TypeScript is notable for its optional typing system, which provides
TypeScript is also notable for its optional typing system, which provides
compile-time type checking and strong tooling support (such as "intellisense,"
code completion, refactoring, and intelligent search). Many code editors
and IDEs support TypeScript either natively or with plugins.
TypeScript is the preferred language for Angular development. Read more about TypeScript at [typescriptlang.org](http://www.typescriptlang.org/).
TypeScript is the preferred language for Angular development, although
you can use other JavaScript dialects such as [ES5](guide/glossary#es5).
Read more about TypeScript at [typescriptlang.org](http://www.typescriptlang.org/).
{@a U}
@ -754,10 +780,6 @@ under the control of a [router](guide/glossary#router).
{@a W}
## Web component
See [Custom element](guide/glossary#custom-element)
{@a X}

View File

@ -220,7 +220,7 @@ Suppose you configured the root injector (marked as A) with _generic_ providers
You create a car component (A) that displays a car constructed from these three generic services.
Then you create a child component (B) that defines its own, _specialized_ providers for `CarService` and `EngineService`
that have special capabilities suitable for whatever is going on in component (B).
that have special capabilites suitable for whatever is going on in component (B).
Component (B) is the parent of another component (C) that defines its own, even _more specialized_ provider for `CarService`.

View File

@ -295,7 +295,7 @@ to every `HttpClient` save method.
### Making a POST request
Apps often POST data to a server. They POST when submitting a form.
In the following example, the `HeroesService` posts when adding a hero to the database.
In the following example, the `HeroService` posts when adding a hero to the database.
<code-example
path="http/src/app/heroes/heroes.service.ts"
@ -313,6 +313,7 @@ It takes two more parameters:
1. `httpOptions` - the method options which, in this case, [specify required headers](#adding-headers).
Of course it catches errors in much the same manner [described above](#error-details).
It also _taps_ the returned observable in order to log the successful POST.
The `HeroesComponent` initiates the actual POST operation by subscribing to
the `Observable` returned by this service method.
@ -346,14 +347,18 @@ the `Observable` returned by this service method.
title="app/heroes/heroes.component.ts (deleteHero)" linenums="false">
</code-example>
The component isn't expecting a result from the delete operation, so it subscribes without a callback. Even though you are not using the result, you still have to subscribe. Calling the `subscribe()` method _executes_ the observable, which is what initiates the DELETE request.
<div class="alert is-important">
You must call _subscribe()_ or nothing happens. Just calling `HeroesService.deleteHero()` **does not initiate the DELETE request.**
You must call _subscribe()_ or nothing happens!
</div>
The component isn't expecting a result from the delete operation and
subscribes without a callback.
The bare `.subscribe()` _seems_ pointless.
In fact, it is essential.
Merely calling `HeroService.deleteHero()` **does not initiate the DELETE request.**
<code-example
path="http/src/app/heroes/heroes.component.ts"
@ -361,7 +366,7 @@ You must call _subscribe()_ or nothing happens. Just calling `HeroesService.dele
</code-example>
{@a always-subscribe}
**Always _subscribe_!**
### Always _subscribe_!
An `HttpClient` method does not begin its HTTP request until you call `subscribe()` on the observable returned by that method. This is true for _all_ `HttpClient` _methods_.
@ -373,7 +378,8 @@ The [`AsyncPipe`](api/common/AsyncPipe) subscribes (and unsubscribes) for you au
All observables returned from `HttpClient` methods are _cold_ by design.
Execution of the HTTP request is _deferred_, allowing you to extend the
observable with additional operations such as `tap` and `catchError` before anything actually happens.
observable with additional operations such as `tap` and `catchError`
before anything actually happens.
Calling `subscribe(...)` triggers execution of the observable and causes
`HttpClient` to compose and send the HTTP request to the server.
@ -398,7 +404,7 @@ req.subscribe();
### Making a PUT request
An app will send a PUT request to completely replace a resource with updated data.
The following `HeroesService` example is just like the POST example.
The following `HeroService` example is just like the POST example.
<code-example
path="http/src/app/heroes/heroes.service.ts"
@ -411,14 +417,14 @@ in order to initiate the request.
## Advanced usage
We have discussed the basic HTTP functionality in `@angular/common/http`, but sometimes you need to do more than make simple requests and get data back.
The above sections detail how to use the basic HTTP functionality in `@angular/common/http`, but sometimes you need to do more than make simple requests and get data back.
### Configuring the request
Other aspects of an outgoing request can be configured via the options object
passed as the last argument to the `HttpClient` method.
You [saw earlier](#adding-headers) that the `HeroesService` sets the default headers by
You [saw earlier](#adding-headers) that the `HeroService` sets the default headers by
passing an options object (`httpOptions`) to its save methods.
You can do more.
@ -448,7 +454,7 @@ Here is a `searchHeroes` method that queries for heroes whose names contain the
region="searchHeroes" linenums="false">
</code-example>
If there is a search term, the code constructs an options object with an HTML URL-encoded search parameter. If the term were "foo", the GET request URL would be `api/heroes/?name=foo`.
If there is a search term, the code constructs an options object with an HTML URL encoded search parameter. If the term were "foo", the GET request URL would be `api/heroes/?name=foo`.
The `HttpParms` are immutable so you'll have to use the `set()` method to update the options.
@ -457,7 +463,7 @@ The `HttpParms` are immutable so you'll have to use the `set()` method to update
The sample includes an _npm package search_ feature.
When the user enters a name in a search-box, the `PackageSearchComponent` sends
a search request for a package with that name to the NPM web API.
a search request for a package with that name to the NPM web api.
Here's a pertinent excerpt from the template:
@ -480,7 +486,7 @@ That's easy to implement with RxJS operators, as shown in this excerpt.
</code-example>
The `searchText$` is the sequence of search-box values coming from the user.
It's defined as an RxJS `Subject`, which means it is a multicasting `Observable`
It's defined as an RxJS `Subject`, which means it is an `Observable`
that can also produce values for itself by calling `next(value)`,
as happens in the `search()` method.
@ -814,7 +820,7 @@ Some folks describe it as a "_one and done_" observable.
But an interceptor can change this to an _observable_ that emits more than once.
A revised version of the `CachingInterceptor` optionally returns an _observable_ that
immediately emits the cached response, sends the request to the NPM web API anyway,
immediately emits the cached response, sends the request to the npm web api anyway,
and emits again later with the updated search results.
<code-example

View File

@ -198,8 +198,9 @@ Its only purpose is to add http service providers to the application as a whole.
## What is the `forRoot()` method?
The `forRoot()` static method is a convention that makes it easy for developers to configure services and providers that are intended to be singletons. A good example of `forRoot()` is the `RouterModule.forRoot()` method.
The `forRoot()` static method is a convention that makes it easy for developers to configure the module's providers.
The `RouterModule.forRoot()` method is a good example.
Apps pass a `Routes` object to `RouterModule.forRoot()` in order to configure the app-wide `Router` service with routes.
`RouterModule.forRoot()` returns a [ModuleWithProviders](api/core/ModuleWithProviders).
You add that result to the `imports` list of the root `AppModule`.
@ -209,9 +210,6 @@ Importing it in any other module, particularly in a lazy-loaded module,
is contrary to the intent and will likely produce a runtime error.
For more information, see [Singleton Services](guide/singleton-services).
For a service, instead of using `forRoot()`, specify `providedIn: 'root'` on the service's `@Injectable()` decorator, which
makes the service automatically available to the whole application and thus singleton by default.
`RouterModule` also offers a `forChild` static method for configuring the routes of lazy-loaded modules.
`forRoot()` and `forChild()` are conventional names for methods that
@ -342,9 +340,7 @@ Define child routes and let the router load module components into that outlet.
## Should I add application-wide providers to the root `AppModule` or the root `AppComponent`?
Define application-wide providers by specifying `providedIn: 'root'` on its `@Injectable()` decorator (in the case of services) or at `InjectionToken` construction (in the case where tokens are provided). Providers that are created this way automatically are made available to the entire application and don't need to be listed in any module.
If a provider cannot be configured in this way (perhaps because it has no sensible default value), then register application-wide providers in the root `AppModule`, not in the `AppComponent`.
Register application-wide providers in the root `AppModule`, not in the `AppComponent`.
Lazy-loaded modules and their components can inject `AppModule` services;
they can't inject `AppComponent` services.
@ -378,10 +374,8 @@ This means that lazy-loaded modules can't reach them.
## Should I add other providers to a module or a component?
Providers should be configured using `@Injectable` syntax. If possible, they should be provided in the application root (`providedIn: 'root'`). Services that are configured this way are lazily loaded if they are only used from a lazily loaded context.
If it's the consumer's decision whether a provider is available application-wide or not,
then register providers in modules (`@NgModule.providers`) instead of registering in components (`@Component.providers`).
In general, prefer registering feature-specific providers in modules (`@NgModule.providers`)
to registering in components (`@Component.providers`).
Register a provider with a component when you _must_ limit the scope of a service instance
to that component and its component tree.

View File

@ -56,7 +56,7 @@ Alternatively, the `subscribe()` method can accept callback function definitions
In either case, a `next` handler is required. The `error` and `complete` handlers are optional.
Note that a `next()` function could receive, for instance, message strings, or event objects, numeric values, or structures, depending on context. As a general term, we refer to data published by an observable as a *stream*. Any type of value can be represented with an observable, and the values are published as a stream.
Note that a `next()` function could receive, for instance, message strings, or event objects, numeric values, or stuctures, depending on context. As a general term, we refer to data published by an observable as a *stream*. Any type of value can be represented with an observable, and the values are published as a stream.
## Creating observables

View File

@ -9,40 +9,27 @@ see the <live-example></live-example>.
<hr>
A provider is an instruction to the DI system on how to obtain a value for a dependency. Most of the time, these dependencies are services that you create and provide.
## Providing a service
If you already have a CLI generated app, create a service using the following CLI command in the root project directory. Replace _User_ with the name of your service.
## Create a service
You can provide services to your app by using the `providers` array in an NgModule.
Consider the default app generated by the CLI. In order to add a user service to it,
you can generate one by entering the following command in the terminal window:
```sh
ng generate service User
```
This command creates the following `UserService` skeleton:
This creates a service called `UserService`. You now need to make the service available in your
app's injector. Update `app.module.ts` by importing it with your other import statements at the top
of the file and adding it to the `providers` array:
<code-example path="providers/src/app/user.service.0.ts" title="src/app/user.service.0.ts" linenums="false"> </code-example>
You can now inject `UserService` anywhere in your application.
The service itself is a class that the CLI generated and that's decorated with `@Injectable`. By default, this decorator is configured with a `providedIn` property, which creates a provider for the service. In this case, `providedIn: 'root'` specifies that the service should be provided in the root injector.
<code-example path="providers/src/app/app.module.ts" title="src/app/app.module.ts" linenums="false">
</code-example>
## Provider scope
When you add a service provider to the root application injector, its available throughout the app. Additionally, these providers are also available to all the classes in the app as long they have the lookup token.
When you add a service provider to the `providers` array of the root module, its available throughout the app. Additionally, when you import a module that has providers, those providers are also available to all the classes in the app as long they have the lookup token. For example, if you import the `HttpClientModule` into your `AppModule`, its providers are then available to the entire app and you can make HTTP requests from anywhere in your app.
You should always provide your service in the root injector unless there is a case where you want the service to be available only if the consumer imports a particular `@NgModule)`.
## providedIn and NgModules
It's also possible to specify that a service should be provided in a particular `@NgModule`. For example, if you don't want `UserService` to be available to applications unless they import a `UserModule` you've created, you can specify that the service should be provided in the module:
<code-example path="providers/src/app/user.service.1.ts" title="src/app/user.service.1.ts" linenums="false"> </code-example>
The example above shows the preferred way to provide a service in a module. This method is preferred because it enables tree-shaking of the service if nothing injects it. If it's not possible to specify in the service which module should provide it, you can also declare a provider for the service within the module:
<code-example path="providers/src/app/user.module.ts" title="src/app/user.module.ts" linenums="false"> </code-example>
## Limiting provider scope by lazy loading modules
@ -88,5 +75,4 @@ Register a provider with a component when you must limit a service instance to a
You may also be interested in:
* [Singleton Services](guide/singleton-services), which elaborates on the concepts covered on this page.
* [Lazy Loading Modules](guide/lazy-loading-ngmodules).
* [Tree-shakable Providers](guide/dependency-injection#tree-shakable-providers).
* [NgModule FAQ](guide/ngmodule-faq).

View File

@ -40,7 +40,7 @@ Older versions produce errors, but newer versions are fine.
Then install the [Angular CLI](https://github.com/angular/angular-cli) globally.
Then **install the [Angular CLI](https://github.com/angular/angular-cli)** globally.
<code-example language="sh" class="code-shell">
@ -60,7 +60,7 @@ Then install the [Angular CLI](https://github.com/angular/angular-cli) globally.
Open a terminal window.
Generate a new project and default app by running the following command:
Generate a new project and skeleton application by running the following commands:
<code-example language="sh" class="code-shell">
@ -69,24 +69,20 @@ Generate a new project and default app by running the following command:
</code-example>
The Angular CLI installs the necessary npm packages, creates the project files, and populates the project with a simple default app. This can take some time.
<div class="l-sub-section">
You can add pre-packaged functionality to a new project by using the `ng add` command. The `ng add` command transforms a project by applying the schematics in the specified package.
For more information, see the [Angular CLI documentation.](https://github.com/angular/angular-cli/wiki/add "Angular CLI documentation")
Angular Material provides schematics for typical app layouts.
See the [Angular Material documentation](https://material.angular.io/guides "Angular Material documentation") for details.
Patience, please.
It takes time to set up a new project; most of it is spent installing npm packages.
</div>
<h2 id='serve'>
Step 3: Serve the application
</h2>
@ -206,17 +202,14 @@ Any files outside of this folder are meant to support building your app.
<div class="file">environment.prod.ts</div>
<div class="file">environment.ts</div>
</div>
<div class="file">browserslist</div>
<div class="file">favicon.ico</div>
<div class="file">index.html</div>
<div class="file">karma.conf.js</div>
<div class="file">main.ts</div>
<div class="file">polyfills.ts</div>
<div class="file">styles.css</div>
<div class="file">test.ts</div>
<div class="file">tsconfig.app.json</div>
<div class="file">tsconfig.spec.json</div>
<div class="file">tslint.json</div>
</div>
</div>
@ -300,18 +293,6 @@ Any files outside of this folder are meant to support building your app.
</td>
</tr>
<tr>
<td>
`browserslist`
</td>
<td>
A configuration file to share [target browsers](https://github.com/browserslist/browserslist) between different front-end tools.
</td>
</tr>
<tr>
<td>
@ -340,19 +321,6 @@ Any files outside of this folder are meant to support building your app.
</td>
</tr>
<tr>
<td>
`karma.conf.js`
</td>
<td>
Unit test configuration for the [Karma test runner](https://karma-runner.github.io),
used when running `ng test`.
</td>
</tr>
<tr>
<td>
@ -423,20 +391,6 @@ Any files outside of this folder are meant to support building your app.
</td>
</tr>
<tr>
<td>
`tslint.json`
</td>
<td>
Additional Linting configuration for [TSLint](https://palantir.github.io/tslint/) together with
[Codelyzer](http://codelyzer.com/), used when running `ng lint`.
Linting helps keep your code style consistent.
</td>
</tr>
</table>
### The root folder
@ -451,23 +405,18 @@ These files go in the root folder next to `src/`.
<div class='children'>
<div class="file">e2e</div>
<div class='children'>
<div class="file">src</div>
<div class='children'>
<div class="file">app.e2e-spec.ts</div>
<div class="file">app.po.ts</div>
</div>
<div class="file">app.e2e-spec.ts</div>
<div class="file">app.po.ts</div>
<div class="file">tsconfig.e2e.json</div>
<div class="file">protractor.conf.js</div>
</div>
<div class="file">node_modules/...</div>
<div class="file">src/...</div>
<div class='children'>
<div class="file">karma.conf.js</div>
</div>
<div class="file">.angular-cli.json</div>
<div class="file">.editorconfig</div>
<div class="file">.gitignore</div>
<div class="file">angular.json</div>
<div class="file">karma.conf.js</div>
<div class="file">package.json</div>
<div class="file">protractor.conf.js</div>
<div class="file">README.md</div>
<div class="file">tsconfig.json</div>
<div class="file">tslint.json</div>
@ -520,6 +469,21 @@ These files go in the root folder next to `src/`.
`package.json` inside of it.
</td>
</tr>
<tr>
<td>
`.angular-cli.json`
</td>
<td>
Configuration for Angular CLI.
In this file you can set several defaults and also configure what files are included
when your project is built.
Check out the official documentation if you want to know more.
</td>
</tr>
<tr>
<td>
@ -543,22 +507,20 @@ These files go in the root folder next to `src/`.
</td>
<td>
Git configuration to make sure autogenerated files are not committed to source control.
Git configuration to make sure autogenerated files are not commited to source control.
</td>
</tr>
<tr>
<td>
`angular.json`
`karma.conf.js`
</td>
<td>
Configuration for Angular CLI.
In this file you can set several defaults and also configure what files are included
when your project is built.
Check out the official documentation if you want to know more.
Unit test configuration for the [Karma test runner](https://karma-runner.github.io),
used when running `ng test`.
</td>
</tr>

View File

@ -940,7 +940,8 @@ with that hero's data values.
A refresh button clears the hero list and the current selected hero before refetching the heroes.
Notice that `hero-list.component.ts` imports `Observable` and the `finalize` operator, while `hero.service.ts` imports `Observable`, `of`, and the `delay` operator from `rxjs`.
Notice that `hero-list.component.ts` imports `Observable` and `finally` while `hero.service.ts` imports `Observable`, `of`,
and `delay` from `rxjs`.
The remaining `HeroListComponent` and `HeroService` implementation details are beyond the scope of this tutorial.
However, the techniques involved are covered elsewhere in the documentation, including the _Tour of Heroes_

View File

@ -340,9 +340,9 @@ It has a great deal of useful information including:
Two older properties are still available. They are less capable than their replacements, discouraged, and may be deprecated in a future Angular version.
**`params`**&mdash;An `Observable` that contains the required and [optional parameters](#optional-route-parameters) specific to the route. Use `paramMap` instead.
**`params`** &mdash; An `Observable` that contains the required and [optional parameters](#optional-route-parameters) specific to the route. Use `paramMap` instead.
**`queryParams`**&mdash;An `Observable` that contains the [query parameters](#query-parameters) available to all routes.
**`queryParams`** &mdash; An `Observable` that contains the [query parameters](#query-parameters) available to all routes.
Use `queryParamMap` instead.
</div>
@ -1619,7 +1619,8 @@ They are distributed across two modules, `AppRoutingModule` and `HeroesRoutingMo
Each routing module augments the route configuration _in the order of import_.
If you list `AppRoutingModule` first, the wildcard route will be registered
_before_ the hero routes.
The wildcard route&mdash;which matches _every_ URL&mdash;will intercept the attempt to navigate to a hero route.
The wildcard route &mdash; which matches _every_ URL &mdash;
will intercept the attempt to navigate to a hero route.
<div class="l-sub-section">
@ -2059,7 +2060,7 @@ The path for the "Heroes" route doesn't have an `:id` token.
The optional route parameters are not separated by "?" and "&" as they would be in the URL query string.
They are **separated by semicolons ";"**
This is *matrix URL* notation&mdash;something you may not have seen before.
This is *matrix URL* notation &mdash; something you may not have seen before.
<div class="l-sub-section">
@ -3148,7 +3149,7 @@ Here's a demo `AuthService`:
Although it doesn't actually log in, it has what you need for this discussion.
It has an `isLoggedIn` flag to tell you whether the user is authenticated.
Its `login` method simulates an API call to an external service by returning an
observable that resolves successfully after a short pause.
Observable that resolves successfully after a short pause.
The `redirectUrl` property will store the attempted URL so you can navigate to it after authenticating.
Revise the `AuthGuard` to call it.
@ -3458,11 +3459,13 @@ Be explicit. Implement the `Resolve` interface with a type of `Crisis`.
Inject the `CrisisService` and `Router` and implement the `resolve()` method.
That method could return a `Promise`, an `Observable`, or a synchronous return value.
The `CrisisService.getCrisis` method returns an observable, in order to prevent the route from loading until the data is fetched.
The `Router` guards require an observable to `complete`, meaning it has emitted all
The `CrisisService.getCrisis` method returns an Observable.
Return that observable to prevent the route from loading until the data is fetched.
The `Router` guards require an Observable to `complete`, meaning it has emitted all
of its values. You use the `take` operator with an argument of `1` to ensure that the
observable completes after retrieving the first value from the observable returned by the
`getCrisis` method. If it doesn't return a valid `Crisis`, navigate the user back to the `CrisisListComponent`,
Observable completes after retrieving the first value from the Observable returned by the
`getCrisis` method.
If it doesn't return a valid `Crisis`, navigate the user back to the `CrisisListComponent`,
canceling the previous in-flight navigation to the `CrisisDetailComponent`.
Import this resolver in the `crisis-center-routing.module.ts`
@ -3499,8 +3502,8 @@ The router looks for that method and calls it if found.
Don't worry about all the ways that the user could navigate away.
That's the router's job. Write this class and let the router take it from there.
1. The observable provided to the Router _must_ complete.
If the observable does not complete, the navigation will not continue.
1. The Observable provided to the Router _must_ complete.
If the Observable does not complete, the navigation will not continue.
The relevant *Crisis Center* code for this milestone follows.
@ -3925,7 +3928,7 @@ The router calls the `preload` method with two arguments:
1. The route to consider.
1. A loader function that can load the routed module asynchronously.
An implementation of `preload` must return an `Observable`.
An implementation of `preload`must return an `Observable`.
If the route should preload, it returns the observable returned by calling the loader function.
If the route should _not_ preload, it returns an `Observable` of `null`.

View File

@ -1,3 +1,5 @@
{@a glob}
# Service worker configuration
#### Prerequisites
@ -7,9 +9,9 @@ A basic understanding of the following:
<hr />
The `src/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. The
CLI processes the configuration file during `ng build --prod`. Manually, you can process
The `src/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. The
CLI processes the configuration file during `ng build --prod`. Manually, you can process
it with the `ngsw-config` tool:
```sh
@ -18,11 +20,10 @@ ngsw-config dist src/ngsw-config.json /base/href
The configuration file uses the JSON format. All file paths must begin with `/`, which is the deployment directory&mdash;usually `dist` in CLI projects.
{@a glob-patterns}
Unless otherwise noted, patterns use a limited glob format:
Patterns use a limited glob format:
* `**` matches 0 or more path segments.
* `*` matches 0 or more characters excluding `/`.
* `*` matches exactly one path segment or filename segment.
* The `!` prefix marks the pattern as being negative, meaning that only files that don't match the pattern will be included.
Example patterns:
@ -31,14 +32,13 @@ Example patterns:
* `/*.html` specifies only HTML files in the root.
* `!/**/*.map` exclude all sourcemaps.
Each section of the configuration file is described below.
Each section of the configuration file is described below.
## `appData`
This section enables you to pass any data you want that describes this particular version of the app.
The `SwUpdate` service includes that data in the update notifications. Many apps use this section to provide additional information for the display of UI popups, notifying users of the available update.
{@a index-file}
## `index`
Specifies the file that serves as the index page to satisfy navigation requests. Usually this is `/index.html`.
@ -92,7 +92,7 @@ The `installMode` determines how these resources are initially cached. The `inst
For resources already in the cache, the `updateMode` determines the caching behavior when a new version of the app is discovered. Any resources in the group that have changed since the previous version are updated in accordance with `updateMode`.
* `prefetch` tells the service worker to download and cache the changed resources immediately.
* `prefetch` tells the service worker to download and cache the changed resources immediately.
* `lazy` tells the service worker to not cache those resources. Instead, it treats them as unrequested and waits until they're requested again before updating them. An `updateMode` of `lazy` is only valid if the `installMode` is also `lazy`.
@ -104,8 +104,7 @@ This section describes the resources to cache, broken up into three groups.
* `versionedFiles` is like `files` but should be used for build artifacts that already include a hash in the filename, which is used for cache busting. The Angular service worker can optimize some aspects of its operation if it can assume file contents are immutable.
* `urls` includes both URLs and URL patterns that will be matched at runtime. These resources are not fetched directly and do not have content hashes, but they will be 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.)_
* `urls` includes both URLs and URL patterns that will be matched at runtime. These resources are not fetched directly and do not have content hashes, but they will be cached according to their HTTP headers. This is most useful for CDNs such as the Google Fonts service.
## `dataGroups`
@ -131,13 +130,12 @@ export interface DataGroup {
Similar to `assetGroups`, every data group has a `name` which uniquely identifies it.
### `urls`
A list of URL patterns. URLs that match these patterns will be cached according to this data group's policy.<br>
_(Negative glob patterns are not supported.)_
A list of URL patterns. URLs that match these patterns will be cached according to this data group's policy.
### `version`
Occasionally APIs change formats in a way that is not backward-compatible. A new version of the app may not be compatible with the old API format and thus may not be compatible with existing cached resources from that API.
`version` provides a mechanism to indicate that the resources being cached have been updated in a backwards-incompatible way, and that the old cache entries&mdash;those from previous versions&mdash;should be discarded.
`version` provides a mechanism to indicate that the resources being cached have been updated in a backwards-incompatible way, and that the old cache entries&mdash;those from previous versions&mdash;should be discarded.
`version` is an integer field and defaults to `0`.
@ -169,38 +167,3 @@ The Angular service worker can use either of two caching strategies for data res
* `freshness` optimizes for currency of data, preferentially fetching requested data from the network. Only if the network times out, according to `timeout`, does the request fall back to the cache. This is useful for resources that change frequently; for example, account balances.
## `navigationUrls`
This optional section enables you to specify a custom list of URLs that will be redirected to the index file.
### Handling navigation requests
The ServiceWorker will redirect 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:
1. Its [mode](https://developer.mozilla.org/en-US/docs/Web/API/Request/mode) is `navigation`.
2. It accepts a `text/html` response (as determined by the value of the `Accept` header).
3. Its URL matches certain criteria (see below).
By default, these criteria are:
1. The URL must not contain a file extension (i.e. a `.`) in the last path segment.
2. The URL must not contain `__`.
### Matching navigation request URLs
While these default criteria are fine in most cases, it is sometimes desirable to configure different rules. For example, you may want to ignore specific routes (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 will be matched at runtime. It can contain both negative patterns (i.e. patterns starting with `!`) and non-negative patterns and URLs.
Only requests whose URLs match _any_ of the non-negative URLs/patterns and _none_ of the negative ones will be considered navigation requests. The URL query will be ignored when matching.
If the field is omitted, it defaults to:
```ts
[
'/**', // Include all URLs.
'!/**/*.*', // Exclude URLs to files.
'!/**/*__*', // Exclude URLs containing `__` in the last segment.
'!/**/*__*/**', // Exclude URLs containing `__` in any other segment.
]
```

Some files were not shown because too many files have changed in this diff Show More