Compare commits
393 Commits
Author | SHA1 | Date | |
---|---|---|---|
2b7116a4f3 | |||
8be20f3a3e | |||
5112669d29 | |||
3d453fe6df | |||
32a6972cdc | |||
2cd5d4c64b | |||
3248fe865f | |||
b3ea6981cd | |||
f698a6bd73 | |||
97d2673eae | |||
4e93c4f87a | |||
b5f85638f7 | |||
efd13d31fc | |||
3a45bef0e7 | |||
5b105544fc | |||
4c5cfecc56 | |||
9d2348b9af | |||
e7bca0751c | |||
45c909a237 | |||
5b76b939af | |||
261593aab1 | |||
c9ce735675 | |||
b7f95bec04 | |||
d02573d05f | |||
8ff6ed6aa3 | |||
6aaf4eac89 | |||
1d0c93622d | |||
acd6c195a0 | |||
53a9a28ec0 | |||
aa8dd74176 | |||
ed6dcce13b | |||
d170e45784 | |||
7033e7eb22 | |||
893123936b | |||
31fcb9e036 | |||
c303d44df6 | |||
73dd43170b | |||
514271ba9c | |||
8d18b49899 | |||
6b0b7d01bf | |||
079773f54e | |||
b5cb120db0 | |||
0fb78d6c94 | |||
a80a8636ba | |||
0878d67757 | |||
5e0890b3af | |||
43bac21301 | |||
4df415060b | |||
039d70efec | |||
2a71496791 | |||
617a329c24 | |||
a00eae0b62 | |||
e54dd741ef | |||
7b4c1cdbe4 | |||
5e4babeaa9 | |||
f661f460bb | |||
44f233c02c | |||
31e8a52722 | |||
e3c9f9d794 | |||
e7c4e94c9a | |||
26dc826821 | |||
287247ef05 | |||
af170d2ae9 | |||
a01ed0d7b4 | |||
a7b94783b5 | |||
789dd6a0da | |||
e5b18e810c | |||
b8f86ad7d5 | |||
6f2e8afaed | |||
699c705a8d | |||
adc869ff88 | |||
46f2dcc470 | |||
2d9c4c1d82 | |||
0757702d63 | |||
174777443d | |||
baf2d9ddbc | |||
da444984a8 | |||
84a3daf609 | |||
c88cdea9ac | |||
7b3bd219f7 | |||
dc76c14e31 | |||
0ffc1d0d21 | |||
3d1b82be67 | |||
dec7e5286f | |||
2f812f31d5 | |||
18bac15ddd | |||
a1fe52b41c | |||
033fc3e6e5 | |||
76854287e5 | |||
972550ee08 | |||
c67f490d28 | |||
edd6cb5865 | |||
7b2617f087 | |||
d9d06899f4 | |||
eccb60cd6e | |||
3420d2923a | |||
6ec91dd4ca | |||
90ddee7a71 | |||
3300331691 | |||
6f3414bd68 | |||
1b0bd6b706 | |||
cfaefa9964 | |||
a48376b26a | |||
e6d8274c38 | |||
40df016390 | |||
eee75c2eea | |||
96aefc5019 | |||
038d823943 | |||
19095835a4 | |||
b560207bf5 | |||
c5de1fb05f | |||
62a9843ed0 | |||
75a162575f | |||
5bf912599f | |||
afd76a80da | |||
bb4627786d | |||
83d67b4a83 | |||
6ba31b9b84 | |||
a1c43b39a2 | |||
af91c21fd9 | |||
c00e7ff128 | |||
3bf2f98c35 | |||
2cabced9fc | |||
b38e8674bc | |||
553f335705 | |||
dde0a32946 | |||
9789cb6507 | |||
bb1fdb6c0f | |||
44b5bf486f | |||
14bfcfb731 | |||
04ebd59961 | |||
6129cfa269 | |||
b8f269414e | |||
8ed83caa19 | |||
aebf65d0ef | |||
b667bd2224 | |||
03e8a31bf5 | |||
800e90e4ed | |||
7290053952 | |||
14890e9117 | |||
06c49b4a6b | |||
d269b111dd | |||
46b160e925 | |||
dcbc28f729 | |||
9bdffb1e5c | |||
155f40c175 | |||
8c446b05d0 | |||
2647f708b7 | |||
fa15814d75 | |||
7a62530ed1 | |||
6ece7db37a | |||
3a2b195a58 | |||
489cef6ea2 | |||
985513351b | |||
8f3dd85600 | |||
6b67cd5620 | |||
0cd4c019cf | |||
7e46a6d99d | |||
85d051f8d5 | |||
c7542a1d09 | |||
2172368eae | |||
2c402d5c99 | |||
35a025fbca | |||
a86850e3f2 | |||
1bcd58cee8 | |||
dd0be7feb7 | |||
3d7303efc0 | |||
716af1059c | |||
a182714703 | |||
17b32b5fd4 | |||
29e1c53a31 | |||
87ce4e997b | |||
2bb9a65351 | |||
6b51ed29ef | |||
b696413a79 | |||
b6aeaceb8e | |||
5ae9b76a9b | |||
82055b2fb8 | |||
44039a4b16 | |||
a445826dad | |||
7f7033bbd7 | |||
27997a16c0 | |||
59c3700c8c | |||
4d93d2406f | |||
d39a2beae1 | |||
c038992fae | |||
8a470b9af9 | |||
399935c32b | |||
97ab52c618 | |||
f69e4e6f77 | |||
9f2ae5d6ff | |||
9eefe25e2f | |||
221782a8a1 | |||
24ca582bc5 | |||
b31a292955 | |||
1d7aa0a92c | |||
0aff4a6919 | |||
f50dede8f7 | |||
0e68c7edf9 | |||
54ef63b0f4 | |||
215ef3c5f4 | |||
5a8eb924ba | |||
c845a7b887 | |||
8b26447c4f | |||
ce196105ce | |||
b9a94c6d02 | |||
ebc71f7caa | |||
f65db20c6d | |||
8f084d7214 | |||
cb848b9410 | |||
d52ae7cbab | |||
9c954ebc62 | |||
f14693b9a4 | |||
f10d6c66c9 | |||
4495a46b99 | |||
ef75fb8ecd | |||
7b6ee5e0d9 | |||
e822394075 | |||
1b6e8411bd | |||
7151eae36d | |||
376ad9c3cd | |||
4aecf9253b | |||
60f58bf051 | |||
10a1e1974b | |||
647d7bdd88 | |||
69a612d402 | |||
221cbd0b47 | |||
ce9d0de840 | |||
18f0c2f1d4 | |||
5bd12c5aa1 | |||
0139b11227 | |||
e061e638cb | |||
dda781ecce | |||
a27c5dd740 | |||
012b535147 | |||
2200884e55 | |||
78e7fdd98d | |||
1e9eeafa9e | |||
9ef9bfe76b | |||
a5f9a86520 | |||
dd664f694c | |||
b66d82e308 | |||
518bca0841 | |||
d7ca263cc4 | |||
e8ae3c5f2e | |||
85a7fe8702 | |||
32c07ceca0 | |||
d3744457ab | |||
fc61284dbe | |||
12fd06916b | |||
9e83822679 | |||
54794f9b31 | |||
897bd18fbc | |||
1ac07757dd | |||
0110de2662 | |||
f166b6d8f6 | |||
09576e9683 | |||
40d785f0a0 | |||
46c03bd866 | |||
d5d8657d30 | |||
8853f13f82 | |||
3166cffd28 | |||
40705f3366 | |||
19bc11139d | |||
31ea254a07 | |||
caf8c0a437 | |||
d6c80871f5 | |||
edc51f76c4 | |||
c529be9f24 | |||
b65e11e3c3 | |||
3a09d01c63 | |||
604d9063c5 | |||
c4c340a7c4 | |||
32aa18be78 | |||
80fa84c177 | |||
e44ba0ffa9 | |||
19a28e599b | |||
14ad7562c6 | |||
0c61a35ea3 | |||
fac20bd8d1 | |||
63e458dd3a | |||
d545bbeee4 | |||
4bb283cbb2 | |||
a08b4b3519 | |||
0e86551a63 | |||
5c738417db | |||
3d9ba19ff8 | |||
8b7a4d7550 | |||
76b755e292 | |||
565a58e261 | |||
7014b67e51 | |||
6f50aad5c4 | |||
ef44f51d58 | |||
9204de96a1 | |||
7c62a8f9ca | |||
a55c6df07b | |||
d33204956f | |||
66d6b53fb1 | |||
e85fa5d4ff | |||
0c00c94f34 | |||
9b29ca95a2 | |||
479d926b4b | |||
b9195289a5 | |||
75b6b0e1ba | |||
2d4f507b61 | |||
3246a8553c | |||
db557221bc | |||
7ea6073534 | |||
1cba5d42d1 | |||
103a5b42ec | |||
fe1793844d | |||
68940f05d8 | |||
53212db3ed | |||
dee16a4355 | |||
6da1446afc | |||
76e3b57a12 | |||
524180c271 | |||
c69e552a83 | |||
2844f2779f | |||
2b44be984e | |||
989ebcbb62 | |||
23e0d65471 | |||
e92fb68f3c | |||
7724f7446a | |||
207f9b6017 | |||
a581773887 | |||
7f2330a968 | |||
aaaeb924ac | |||
98a68ad3e7 | |||
36d3062a42 | |||
83b19bf1a2 | |||
e6f1b04cd5 | |||
6aaca21c27 | |||
50c4ec6687 | |||
9a2d1fab84 | |||
8052de07e2 | |||
40aaa42f44 | |||
35f8bfce8b | |||
4b05ebc804 | |||
e30f494a39 | |||
1d3e22766a | |||
c0955975f4 | |||
9515f171b4 | |||
1efaac5cb0 | |||
d27181fcdd | |||
9e34670b25 | |||
5039faff8d | |||
44c6534f3c | |||
09970d52e8 | |||
95a9d67599 | |||
fde016bc38 | |||
11a208f55c | |||
1db3ac457c | |||
02491a6ce8 | |||
dca713c087 | |||
eb6281f5b4 | |||
a4a423a083 | |||
ba5b3af077 | |||
64e7af4e43 | |||
d2d84c4460 | |||
29f5582af5 | |||
63bdfca580 | |||
361109d80f | |||
b7a099d27e | |||
f83dfd6f5a | |||
dd36f3ac99 | |||
0d6fd134d4 | |||
bbb27b5517 | |||
7ca611cd12 | |||
c12b6fa028 | |||
a29dc961a2 | |||
0de5d79bf6 | |||
f57e77eeb4 | |||
2b5d52fbdc | |||
81332150aa | |||
c6b29f4c6d | |||
261dc04d8e | |||
15e397816f | |||
f96a81a818 | |||
4f38419e33 | |||
119004c7d4 | |||
d171006083 | |||
19e8570ac0 | |||
93abc35213 | |||
d7be38f84b | |||
2d38623974 | |||
5306330d85 | |||
c150354464 | |||
7217525da4 | |||
b6e8d19313 | |||
6c0cca093a | |||
f2360aab9d | |||
d7b4172678 |
16
.bazelrc
16
.bazelrc
@ -36,22 +36,6 @@ build --incompatible_strict_action_env
|
||||
run --incompatible_strict_action_env
|
||||
test --incompatible_strict_action_env
|
||||
|
||||
###############################
|
||||
# Saucelabs support #
|
||||
# Turn on these settings with #
|
||||
# --config=saucelabs #
|
||||
###############################
|
||||
|
||||
# Expose SauceLabs environment to actions
|
||||
# These environment variables are needed by
|
||||
# web_test_karma to run on Saucelabs
|
||||
test:saucelabs --action_env=SAUCE_USERNAME
|
||||
test:saucelabs --action_env=SAUCE_ACCESS_KEY
|
||||
test:saucelabs --action_env=SAUCE_READY_FILE
|
||||
test:saucelabs --action_env=SAUCE_PID_FILE
|
||||
test:saucelabs --action_env=SAUCE_TUNNEL_IDENTIFIER
|
||||
test:saucelabs --define=KARMA_WEB_TEST_MODE=SL_REQUIRED
|
||||
|
||||
###############################
|
||||
# Release support #
|
||||
# Turn on these settings with #
|
||||
|
@ -37,5 +37,5 @@ build --verbose_failures=true
|
||||
# > Example job: https://circleci.com/gh/angular/angular/385517
|
||||
# We expect that TypeScript compilations will parallelize wider than the number of local cores anyway
|
||||
# so we should saturate remote workers with TS compilations
|
||||
build --strategy=TypeScriptCompile=standalone
|
||||
build --strategy=AngularTemplateCompile=standalone
|
||||
build --strategy=AngularTemplateCompile=local
|
||||
build --strategy=TypeScriptCompile=local
|
||||
|
@ -35,7 +35,7 @@ var_4: &init_environment
|
||||
# Overwrite the yarn installed in the docker container with our own version.
|
||||
command: |
|
||||
./.circleci/env.sh
|
||||
ourYarn=$(realpath ./third_party/github.com/yarnpkg/yarn/releases/download/v1.13.0/bin/yarn.js)
|
||||
ourYarn=$(realpath ./third_party/github.com/yarnpkg/yarn/releases/download/v1.17.3/bin/yarn.js)
|
||||
sudo chmod a+x $ourYarn
|
||||
sudo ln -fs $ourYarn /usr/local/bin/yarn
|
||||
echo "Yarn version: $(yarn --version)"
|
||||
@ -143,7 +143,7 @@ var_14: ¬ify_dev_infra_on_fail
|
||||
|
||||
# Cache key for the Material unit tests job. **Note** when updating the SHA in the cache keys,
|
||||
# also update the SHA for the "MATERIAL_REPO_COMMIT" environment variable.
|
||||
var_15: &material_unit_tests_cache_key v4-angular-material-701302dc482d7e4b77990b24e3b5ab330bbf1aa5
|
||||
var_15: &material_unit_tests_cache_key v4-angular-material-18b9ef3f5529f0fa8f034944681486447af7b879
|
||||
var_16: &material_unit_tests_cache_key_short v4-angular-material
|
||||
|
||||
version: 2
|
||||
@ -198,13 +198,6 @@ jobs:
|
||||
# Setup remote execution and run RBE-compatible tests.
|
||||
- *setup_bazel_remote_execution
|
||||
- run: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only
|
||||
- run: mkdir ~/testlogs
|
||||
- run: cp -Lr dist/testlogs/* ~/testlogs
|
||||
- store_test_results:
|
||||
# Bazel always writes test.xml files under this directory
|
||||
path: ~/testlogs
|
||||
- store_artifacts:
|
||||
path: ~/testlogs
|
||||
|
||||
# Temporary job to test what will happen when we flip the Ivy flag to true
|
||||
test_ivy_aot:
|
||||
@ -256,23 +249,19 @@ jobs:
|
||||
- *init_environment
|
||||
- *setup_circleci_bazel_config
|
||||
- run:
|
||||
name: Preparing environment for running tests on Saucelabs.
|
||||
command: setSecretVar SAUCE_ACCESS_KEY $(echo $SAUCE_ACCESS_KEY | rev)
|
||||
- run:
|
||||
name: Starting Saucelabs tunnel
|
||||
command: ./scripts/saucelabs/start-tunnel.sh
|
||||
background: true
|
||||
# Waits for the Saucelabs tunnel to be ready. This ensures that we don't run tests
|
||||
# too early without Saucelabs not being ready.
|
||||
- run: ./scripts/saucelabs/wait-for-tunnel.sh
|
||||
# All web tests are contained within a single //:test_web_all target for Saucelabs
|
||||
# as running each set of tests as a separate target will attempt to acquire too
|
||||
# many browsers on Saucelabs (7 per target currently) and some tests will always
|
||||
# fail to acquire browsers. For example:
|
||||
# 14 02 2019 19:52:33.170:WARN [launcher]: chrome beta on SauceLabs have not captured in 180000 ms, killing.
|
||||
# //packages/forms/test:web_test_sauce TIMEOUT in 315.0s
|
||||
- run: yarn bazel test --config=saucelabs //:test_web_all
|
||||
- run: ./scripts/saucelabs/stop-tunnel.sh
|
||||
name: Run Bazel tests in saucelabs
|
||||
# All web tests are contained within a single //:test_web_all target for Saucelabs
|
||||
# as running each set of tests as a separate target will attempt to acquire too
|
||||
# many browsers on Saucelabs (7 per target currently) and some tests will always
|
||||
# fail to acquire browsers. For example:
|
||||
# 14 02 2019 19:52:33.170:WARN [launcher]: chrome beta on SauceLabs have not captured in 180000 ms, killing.
|
||||
# //packages/forms/test:web_test_sauce TIMEOUT in 315.0s
|
||||
command: |
|
||||
./scripts/saucelabs/run-bazel-via-tunnel.sh \
|
||||
--tunnel-id angular-${CIRCLE_BUILD_NUM}-${CIRCLE_NODE_INDEX} \
|
||||
--username $SAUCE_USERNAME \
|
||||
--key $(echo $SAUCE_ACCESS_KEY | rev) \
|
||||
yarn bazel test //:test_web_all
|
||||
- *notify_dev_infra_on_fail
|
||||
|
||||
test_aio:
|
||||
@ -321,7 +310,7 @@ jobs:
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Build aio (with local Angular packages)
|
||||
- run: yarn --cwd aio build-local --progress=false
|
||||
- run: yarn --cwd aio build-local-ci
|
||||
# Run unit tests
|
||||
- run: yarn --cwd aio test --progress=false --watch=false
|
||||
# Run e2e tests
|
||||
@ -340,7 +329,7 @@ jobs:
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Build aio with Ivy (using local Angular packages)
|
||||
- run: yarn --cwd aio build-with-ivy --progress=false
|
||||
- run: yarn --cwd aio build-with-ivy-ci
|
||||
# Run unit tests
|
||||
- run: yarn --cwd aio test --progress=false --watch=false
|
||||
# Run e2e tests
|
||||
@ -673,7 +662,10 @@ workflows:
|
||||
version: 2
|
||||
default_workflow:
|
||||
jobs:
|
||||
- setup
|
||||
- setup:
|
||||
filters:
|
||||
branches:
|
||||
ignore: g3
|
||||
- lint:
|
||||
requires:
|
||||
- setup
|
||||
@ -784,9 +776,3 @@ workflows:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
# TODO:
|
||||
# - don't build the g3 branch
|
||||
# - verify that we are bootstrapping with the right yarn version coming from the docker image
|
||||
# - check local chrome version pulled from docker image
|
||||
# - remove /tools/ngcontainer
|
||||
|
@ -61,6 +61,7 @@ else
|
||||
setPublicVar SAUCE_USERNAME "angular-ci";
|
||||
setSecretVar SAUCE_ACCESS_KEY "9b988f434ff8-fbca-8aa4-4ae3-35442987";
|
||||
fi
|
||||
# TODO(josephperrott): Remove environment variables once all saucelabs tests are via bazel method.
|
||||
setPublicVar SAUCE_LOG_FILE /tmp/angular/sauce-connect.log
|
||||
setPublicVar SAUCE_READY_FILE /tmp/angular/sauce-connect-ready-file.lock
|
||||
setPublicVar SAUCE_PID_FILE /tmp/angular/sauce-connect-pid-file.lock
|
||||
@ -79,7 +80,7 @@ setPublicVar MATERIAL_REPO_TMP_DIR "/tmp/material2"
|
||||
setPublicVar MATERIAL_REPO_URL "https://github.com/angular/material2.git"
|
||||
setPublicVar MATERIAL_REPO_BRANCH "master"
|
||||
# **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI "config.yml".
|
||||
setPublicVar MATERIAL_REPO_COMMIT "701302dc482d7e4b77990b24e3b5ab330bbf1aa5"
|
||||
setPublicVar MATERIAL_REPO_COMMIT "18b9ef3f5529f0fa8f034944681486447af7b879"
|
||||
|
||||
# Source `$BASH_ENV` to make the variables available immediately.
|
||||
source $BASH_ENV;
|
||||
|
@ -1,126 +0,0 @@
|
||||
# escape=`
|
||||
|
||||
ARG core=mcr.microsoft.com/windows/servercore:1809
|
||||
ARG target=mcr.microsoft.com/powershell:windowsservercore-1809
|
||||
|
||||
FROM $core as download
|
||||
|
||||
ARG node_version=10.13.0
|
||||
ARG yarn_version=1.13.0
|
||||
|
||||
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
||||
|
||||
ENV GPG_VERSION 2.3.4
|
||||
|
||||
RUN Invoke-WebRequest $('https://files.gpg4win.org/gpg4win-vanilla-{0}.exe' -f $env:GPG_VERSION) -OutFile 'gpg4win.exe' -UseBasicParsing ; `
|
||||
Start-Process .\gpg4win.exe -ArgumentList '/S' -NoNewWindow -Wait
|
||||
|
||||
RUN @( `
|
||||
'94AE36675C464D64BAFA68DD7434390BDBE9B9C5', `
|
||||
'FD3A5288F042B6850C66B31F09FE44734EB7990E', `
|
||||
'71DCFD284A79C3B38668286BC97EC7A07EDE3FC1', `
|
||||
'DD8F2338BAE7501E3DD5AC78C273792F7D83545D', `
|
||||
'C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8', `
|
||||
'B9AE9905FFD7803F25714661B63B535A4C206CA9', `
|
||||
'77984A986EBC2AA786BC0F66B01FBB92821C587A', `
|
||||
'8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600', `
|
||||
'4ED778F539E3634C779C87C6D7062848A1AB005C', `
|
||||
'A48C2BEE680E841632CD4E44F07496B3EB3C1762', `
|
||||
'B9E2F5981AA6E0CD28160D9FF13993A75599653C' `
|
||||
) | foreach { `
|
||||
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys $_ ; `
|
||||
}
|
||||
|
||||
ENV NODE_VERSION=$node_version
|
||||
|
||||
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/SHASUMS256.txt.asc' -f $env:NODE_VERSION) -OutFile 'SHASUMS256.txt.asc' -UseBasicParsing ; `
|
||||
gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc
|
||||
|
||||
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f $env:NODE_VERSION) -OutFile 'node.zip' -UseBasicParsing ; `
|
||||
$sum = $(cat SHASUMS256.txt.asc | sls $(' node-v{0}-win-x64.zip' -f $env:NODE_VERSION)) -Split ' ' ; `
|
||||
if ((Get-FileHash node.zip -Algorithm sha256).Hash -ne $sum[0]) { Write-Error 'SHA256 mismatch' } ; `
|
||||
Expand-Archive node.zip -DestinationPath C:\ ; `
|
||||
Rename-Item -Path $('C:\node-v{0}-win-x64' -f $env:NODE_VERSION) -NewName 'C:\nodejs'
|
||||
|
||||
ENV YARN_VERSION=$yarn_version
|
||||
|
||||
RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; `
|
||||
Invoke-WebRequest $('https://yarnpkg.com/downloads/{0}/yarn-{0}.msi' -f $env:YARN_VERSION) -OutFile yarn.msi -UseBasicParsing ; `
|
||||
$sig = Get-AuthenticodeSignature yarn.msi ; `
|
||||
if ($sig.Status -ne 'Valid') { Write-Error 'Authenticode signature is not valid' } ; `
|
||||
Write-Output $sig.SignerCertificate.Thumbprint ; `
|
||||
if (@( `
|
||||
'7E253367F8A102A91D04829E37F3410F14B68A5F', `
|
||||
'AF764E1EA56C762617BDC757C8B0F3780A0CF5F9' `
|
||||
) -notcontains $sig.SignerCertificate.Thumbprint) { Write-Error 'Unknown signer certificate' } ; `
|
||||
Start-Process msiexec.exe -ArgumentList '/i', 'yarn.msi', '/quiet', '/norestart' -NoNewWindow -Wait
|
||||
|
||||
ENV GIT_VERSION 2.20.1
|
||||
ENV GIT_DOWNLOAD_URL https://github.com/git-for-windows/git/releases/download/v${GIT_VERSION}.windows.1/MinGit-${GIT_VERSION}-busybox-64-bit.zip
|
||||
ENV GIT_SHA256 9817ab455d9cbd0b09d8664b4afbe4bbf78d18b556b3541d09238501a749486c
|
||||
|
||||
RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; `
|
||||
Invoke-WebRequest -UseBasicParsing $env:GIT_DOWNLOAD_URL -OutFile git.zip; `
|
||||
if ((Get-FileHash git.zip -Algorithm sha256).Hash -ne $env:GIT_SHA256) {exit 1} ; `
|
||||
Expand-Archive git.zip -DestinationPath C:\git; `
|
||||
Remove-Item git.zip
|
||||
|
||||
FROM $target as baseimage
|
||||
|
||||
ENV NPM_CONFIG_LOGLEVEL info
|
||||
|
||||
COPY --from=download /nodejs /nodejs
|
||||
COPY --from=download [ "/Program Files (x86)/yarn", "/yarn" ]
|
||||
COPY --from=download /git /git
|
||||
|
||||
ARG SETX=/M
|
||||
RUN setx %SETX% PATH "%PATH%;C:\nodejs;C:\yarn\bin;C:\git\cmd;C:\git\mingw64\bin;C:\git\usr\bin"
|
||||
|
||||
CMD [ "node.exe" ]
|
||||
|
||||
FROM baseimage
|
||||
|
||||
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
||||
|
||||
# Install Bazel prereqs on Windows (https://docs.bazel.build/versions/master/install-windows.html)
|
||||
|
||||
# Install MSYS2
|
||||
RUN Invoke-WebRequest -UseBasicParsing 'https://www.7-zip.org/a/7z1805-x64.exe' -OutFile 7z.exe; `
|
||||
Start-Process -FilePath 'C:\\7z.exe' -ArgumentList '/S', '/D=C:\\7zip0' -NoNewWindow -Wait; `
|
||||
Invoke-WebRequest -UseBasicParsing 'http://repo.msys2.org/distrib/x86_64/msys2-base-x86_64-20180531.tar.xz' -OutFile msys2.tar.xz; `
|
||||
Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'e', 'msys2.tar.xz' -Wait; `
|
||||
Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'x', 'msys2.tar', '-oC:\\' -Wait; `
|
||||
Remove-Item msys2.tar.xz; `
|
||||
Remove-Item msys2.tar; `
|
||||
Remove-Item 7z.exe; `
|
||||
Remove-Item -Recurse 7zip; `
|
||||
[Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\msys64\usr\bin', [System.EnvironmentVariableTarget]::Machine); `
|
||||
[Environment]::SetEnvironmentVariable('BAZEL_SH', 'C:\msys64\usr\bin\bash.exe', [System.EnvironmentVariableTarget]::Machine)
|
||||
|
||||
# Install MSYS2 packages
|
||||
RUN C:\msys64\usr\bin\bash.exe -l -c \"pacman --needed --noconfirm -S zip unzip patch diffutils git\"
|
||||
|
||||
# Install VS Build Tools (required to build C++ targets)
|
||||
RUN Invoke-WebRequest -UseBasicParsing https://download.visualstudio.microsoft.com/download/pr/df649173-11e9-4af2-8eb7-0eb02ba8958a/cadb5bdac41e55bb8f6a6b7c45273370/vs_buildtools.exe -OutFile vs_BuildTools.exe; `
|
||||
# Installer won't detect DOTNET_SKIP_FIRST_TIME_EXPERIENCE if ENV is used, must use setx /M
|
||||
setx /M DOTNET_SKIP_FIRST_TIME_EXPERIENCE 1; `
|
||||
Start-Process vs_BuildTools.exe `
|
||||
-ArgumentList `
|
||||
'--add', 'Microsoft.VisualStudio.Workload.VCTools', `
|
||||
'--add', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', `
|
||||
'--add', 'Microsoft.Component.VC.Runtime.UCRTSDK', `
|
||||
'--add', 'Microsoft.VisualStudio.Component.Windows10SDK.17763', `
|
||||
'--quiet', '--norestart', '--nocache' `
|
||||
-NoNewWindow -Wait; `
|
||||
Remove-Item -Force vs_buildtools.exe; `
|
||||
Remove-Item -Force -Recurse \"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\"; `
|
||||
Remove-Item -Force -Recurse ${Env:TEMP}\*; `
|
||||
Remove-Item -Force -Recurse \"${Env:ProgramData}\Package Cache\"; `
|
||||
[Environment]::SetEnvironmentVariable('BAZEL_VC', \"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\BuildTools\VC\", [System.EnvironmentVariableTarget]::Machine)
|
||||
|
||||
# Install Python (required to build Python targets)
|
||||
RUN Invoke-WebRequest -UseBasicParsing https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile python-3.5.1.exe; `
|
||||
Start-Process python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait; `
|
||||
Remove-Item -Force python-3.5.1.exe
|
||||
|
||||
CMD ["cmd.exe"]
|
@ -1,33 +0,0 @@
|
||||
# CodeFresh configuration
|
||||
|
||||
[](https://g.codefresh.io/public/accounts/angular/pipelines/angular/angular/angular)
|
||||
|
||||
This folder contains configuration for the [CodeFresh](<https://codefresh.io/>) based CI checks for this repository.
|
||||
|
||||
## The build pipeline
|
||||
|
||||
CodeFresh uses a several pipeline for each repository. The `codefresh.yml` file defines pipeline [build steps](https://codefresh.io/docs/docs/configure-ci-cd-pipeline/introduction-to-codefresh-pipelines/) for this repository.
|
||||
|
||||
Run results can be seen in the GitHub checks interface and in the [public pipeline](https://g.codefresh.io/public/accounts/angular/pipelines/angular/angular/angular)
|
||||
|
||||
Although most configuration is done via `pipeline.yml`, some options are only available in the online [pipeline settings](https://g.codefresh.io/pipelines/angular/services?repoOwner=angular&repoName=angular&project=angular%2Fangular&context=github&serviceName=angular%2Fangular), which needs a login to access.
|
||||
|
||||
|
||||
## Caretaker
|
||||
|
||||
CodeFresh status can be found at <http://status.codefresh.io/>.
|
||||
|
||||
Issues related to the CodeFresh setup should be escalated to the Tools Team via the current caretaker, followed by Alex Eagle and Filipe Silva.
|
||||
|
||||
## Rollout strategy
|
||||
|
||||
Currently it is only used for tests on Windows platforms, on the master branch, and without pushing user-facing reports. It's only possible to see current builds in the [public pipeline dashboard](https://g.codefresh.io/public/accounts/angular/pipelines/angular/angular/angular).
|
||||
|
||||
After a week or two of running like this, we should reassess how stable and reliable it is.
|
||||
|
||||
Next steps include:
|
||||
- building PRs
|
||||
- showing build status publicly
|
||||
- blocking PRs that break the build
|
||||
- expanding the test suite
|
||||
|
@ -1,38 +0,0 @@
|
||||
# These options are enabled when running on CI
|
||||
# We do this by copying this file to /etc/bazel.bazelrc at the start of the build.
|
||||
# See documentation in /docs/BAZEL.md
|
||||
|
||||
# Save built files and downloaded repositories in a location that can be cached by CodeFresh and
|
||||
# shared between builds. This helps speed up the analysis time significantly with Bazel managed node
|
||||
# dependencies on the CI.
|
||||
# https://codefresh.io/docs/docs/configure-ci-cd-pipeline/introduction-to-codefresh-pipelines/#caching-the-artifacts-of-your-build-system
|
||||
build --repository_cache=C:/codefresh/volume/bazel_repository_cache
|
||||
# Setting the output_base to a Docker volume is currently broken because of a Docker bug on Windows:
|
||||
# https://github.com/moby/moby/issues/37024
|
||||
# This affects Bazel because bazel_output_base\external\bazel_tools is an absolute path junction.
|
||||
# When its fixed we can uncomment this line, and use a different output_base for Ivy tests (they
|
||||
# use a separate compiler and destructively replace the cache).
|
||||
# startup --output_base=C:/codefresh/volume/bazel_output_base
|
||||
|
||||
# Don't be spammy in the logs
|
||||
# TODO(gmagolan): Hide progress again once build performance improves
|
||||
# Presently, CircleCI can timeout during bazel test ... with the following
|
||||
# error: Too long with no output (exceeded 10m0s)
|
||||
build --noshow_progress
|
||||
|
||||
# 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
|
||||
|
||||
# Workaround https://github.com/bazelbuild/bazel/issues/3645
|
||||
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
|
||||
# Limit Bazel to consuming resources that fit in CodeFresh VMs
|
||||
# TODO(filipesilva): determine the correct memory limit
|
||||
build --local_resources=10240,8.0,1.0
|
||||
|
||||
# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309
|
||||
test --flaky_test_attempts=2
|
||||
|
||||
# More details on failures
|
||||
build --verbose_failures=true
|
@ -1,28 +0,0 @@
|
||||
version: '1.0'
|
||||
|
||||
steps:
|
||||
BuildImage:
|
||||
title: Build Docker image
|
||||
type: build
|
||||
image_name: node-bazel-windows
|
||||
working_directory: ./.codefresh
|
||||
no_cf_cache: true
|
||||
build_arguments:
|
||||
- node_version=10.13.0
|
||||
- yarn_version=1.13.0
|
||||
dockerfile: ./Dockerfile.win-1809
|
||||
|
||||
RunTests:
|
||||
title: Run Bazel tests
|
||||
image: ${{BuildImage}}
|
||||
commands:
|
||||
# Install dependencies
|
||||
- yarn install --frozen-lockfile --non-interactive --network-timeout 100000 --no-progress
|
||||
# Add Bazel CI config
|
||||
- copy .codefresh\bazel.rc %ProgramData%\bazel.bazelrc
|
||||
# Run tests
|
||||
# At the moment 'browser:chromium-local' are broken in CI while locally they work
|
||||
# VE
|
||||
- yarn bazel test --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only,-browser:chromium-local //...
|
||||
# Ivy
|
||||
- yarn bazel test --define=compile=aot --build_tag_filters=-no-ivy-aot,-fixme-ivy-aot --test_tag_filters=-no-ivy-aot,-fixme-ivy-aot,-browser:chromium-local //...
|
92
.github/CODEOWNERS
vendored
92
.github/CODEOWNERS
vendored
@ -101,7 +101,6 @@
|
||||
#
|
||||
# - brandonroberts
|
||||
# - gkalpak
|
||||
# - jenniferfell
|
||||
# - petebacondarwin
|
||||
|
||||
|
||||
@ -349,10 +348,9 @@
|
||||
|
||||
|
||||
# ===========================================================
|
||||
# @angular/fw-dev-infra
|
||||
# @angular/dev-infra-framework
|
||||
# ===========================================================
|
||||
#
|
||||
# - alexeagle
|
||||
# - devversion
|
||||
# - filipesilva
|
||||
# - gkalpak
|
||||
@ -419,6 +417,7 @@
|
||||
# ================================================
|
||||
|
||||
/packages/compiler/** @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/examples/compiler/** @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/compiler-cli/** @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/aot-compiler.md @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
|
||||
@ -454,8 +453,10 @@
|
||||
# ================================================
|
||||
|
||||
/packages/core/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/examples/core/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/common/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/platform-browser/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/examples/platform-browser/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/platform-browser-dynamic/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/platform-webworker/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/platform-webworker-dynamic/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -516,6 +517,8 @@
|
||||
|
||||
/aio/content/guide/hierarchical-dependency-injection.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/hierarchical-dependency-injection/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/providers-viewproviders/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/resolution-modifiers/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
|
||||
/aio/content/guide/lazy-loading-ngmodules.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/lazy-loading-ngmodules/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -550,8 +553,10 @@
|
||||
/aio/content/examples/attribute-binding/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/two-way-binding/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/built-in-directives/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/built-in-directives/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/template-reference-variables/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/inputs-outputs/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/inputs-outputs/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/template-expression-operators/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
|
||||
|
||||
@ -587,6 +592,7 @@
|
||||
|
||||
/packages/common/http/** @angular/fw-http @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/http/** @angular/fw-http @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/examples/http/** @angular/fw-http @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/http.md @angular/fw-http @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/http/** @angular/fw-http @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/http/** @angular/fw-http @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -609,6 +615,7 @@
|
||||
# ================================================
|
||||
|
||||
/packages/forms/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/examples/forms/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/forms.md @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/forms/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/forms/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -652,6 +659,7 @@
|
||||
# ================================================
|
||||
|
||||
/packages/router/** @angular/fw-router @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/examples/router/** @angular/fw-router @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/router.md @angular/fw-router @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/router/** @angular/fw-router @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/router/** @angular/fw-router @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -663,6 +671,7 @@
|
||||
# ================================================
|
||||
|
||||
/packages/service-worker/** @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/examples/service-worker/** @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/service-worker-getting-started.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/service-worker-getting-started/** @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/app-shell.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -689,6 +698,7 @@
|
||||
/aio/content/examples/upgrade-phonecat-2-hybrid/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/upgrade-phonecat-3-final/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/upgrade-performance.md @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/upgrade-setup.md @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/ajs-quick-reference.md @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/ajs-quick-reference/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
|
||||
@ -777,7 +787,6 @@ testing/** @angular/fw-test
|
||||
/aio/tools/** @angular/docs-infra @angular/framework-global-approvers
|
||||
|
||||
# Hidden docs
|
||||
/aio/content/guide/change-log.md @angular/docs-infra @angular/framework-global-approvers
|
||||
/aio/content/guide/docs-style-guide.md @angular/docs-infra @angular/framework-global-approvers
|
||||
/aio/content/examples/docs-style-guide/** @angular/docs-infra @angular/framework-global-approvers
|
||||
/aio/content/images/guide/docs-style-guide/** @angular/docs-infra @angular/framework-global-approvers
|
||||
@ -790,9 +799,8 @@ testing/** @angular/fw-test
|
||||
# Docs: getting started & tutorial
|
||||
# ================================================
|
||||
|
||||
/aio/content/guide/quickstart.md @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/cli-quickstart/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/cli-quickstart/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/setup-local.md @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/setup-local/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/tutorial/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/toh/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/toh-pt0/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -804,8 +812,8 @@ testing/** @angular/fw-test
|
||||
/aio/content/examples/toh-pt6/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/getting-started-v0/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/getting-started/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/getting-started/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/getting-started/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/start/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/start/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
|
||||
|
||||
# ================================================
|
||||
@ -831,11 +839,11 @@ testing/** @angular/fw-test
|
||||
/aio/content/guide/npm-packages.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/browser-support.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/typescript-configuration.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/setup.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/setup/** @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/build.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/build/** @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/deployment.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/images/guide/deployment/** @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/file-structure.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/releases.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/updating.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -881,42 +889,34 @@ testing/** @angular/fw-test
|
||||
# Build & CI Owners
|
||||
# ================================================
|
||||
|
||||
/* @angular/fw-dev-infra
|
||||
/.buildkite/** @angular/fw-dev-infra
|
||||
/.circleci/** @angular/fw-dev-infra
|
||||
/.codefresh/** @angular/fw-dev-infra
|
||||
/.devcontainer/** @angular/fw-dev-infra
|
||||
/.github/** @angular/fw-dev-infra
|
||||
/.vscode/** @angular/fw-dev-infra
|
||||
/docs/BAZEL.md @angular/fw-dev-infra
|
||||
/packages/* @angular/fw-dev-infra
|
||||
/scripts/** @angular/fw-dev-infra
|
||||
/third_party/** @angular/fw-dev-infra
|
||||
/tools/build/** @angular/fw-dev-infra
|
||||
/tools/cjs-jasmine/** @angular/fw-dev-infra
|
||||
/tools/gulp-tasks/** @angular/fw-dev-infra
|
||||
/tools/ngcontainer/** @angular/fw-dev-infra
|
||||
/tools/npm/** @angular/fw-dev-infra
|
||||
/tools/npm_workspace/** @angular/fw-dev-infra
|
||||
/tools/public_api_guard/** @angular/fw-dev-infra
|
||||
/tools/rxjs/** @angular/fw-dev-infra
|
||||
/tools/source-map-test/** @angular/fw-dev-infra
|
||||
/tools/symbol-extractor/** @angular/fw-dev-infra
|
||||
/tools/testing/** @angular/fw-dev-infra
|
||||
/tools/ts-api-guardian/** @angular/fw-dev-infra
|
||||
/tools/tslint/** @angular/fw-dev-infra
|
||||
/tools/validate-commit-message/** @angular/fw-dev-infra
|
||||
/tools/yarn/** @angular/fw-dev-infra
|
||||
/tools/*
|
||||
*.bzl @angular/fw-dev-infra
|
||||
|
||||
|
||||
|
||||
# ================================================
|
||||
# Material CI
|
||||
# ================================================
|
||||
|
||||
/tools/material-ci/** @angular/fw-core @angular/framework-global-approvers
|
||||
/* @angular/dev-infra-framework
|
||||
/.buildkite/** @angular/dev-infra-framework
|
||||
/.circleci/** @angular/dev-infra-framework
|
||||
/.devcontainer/** @angular/dev-infra-framework
|
||||
/.github/** @angular/dev-infra-framework
|
||||
/.vscode/** @angular/dev-infra-framework
|
||||
/docs/BAZEL.md @angular/dev-infra-framework
|
||||
/packages/* @angular/dev-infra-framework
|
||||
/packages/examples/test-utils/** @angular/dev-infra-framework
|
||||
/scripts/** @angular/dev-infra-framework
|
||||
/third_party/** @angular/dev-infra-framework
|
||||
/tools/build/** @angular/dev-infra-framework
|
||||
/tools/cjs-jasmine/** @angular/dev-infra-framework
|
||||
/tools/gulp-tasks/** @angular/dev-infra-framework
|
||||
/tools/ngcontainer/** @angular/dev-infra-framework
|
||||
/tools/npm/** @angular/dev-infra-framework
|
||||
/tools/npm_workspace/** @angular/dev-infra-framework
|
||||
/tools/public_api_guard/** @angular/dev-infra-framework
|
||||
/tools/rxjs/** @angular/dev-infra-framework
|
||||
/tools/source-map-test/** @angular/dev-infra-framework
|
||||
/tools/symbol-extractor/** @angular/dev-infra-framework
|
||||
/tools/testing/** @angular/dev-infra-framework
|
||||
/tools/ts-api-guardian/** @angular/dev-infra-framework
|
||||
/tools/tslint/** @angular/dev-infra-framework
|
||||
/tools/validate-commit-message/** @angular/dev-infra-framework
|
||||
/tools/yarn/** @angular/dev-infra-framework
|
||||
/tools/* @angular/dev-infra-framework
|
||||
*.bzl @angular/dev-infra-framework
|
||||
|
||||
|
||||
|
||||
|
127
CHANGELOG.md
127
CHANGELOG.md
@ -1,5 +1,85 @@
|
||||
<a name="8.2.5"></a>
|
||||
## [8.2.5](https://github.com/angular/angular/compare/8.2.4...8.2.5) (2019-09-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **common:** HttpParams fromObject accepts ReadonlyArray<string> ([#31072](https://github.com/angular/angular/issues/31072)) ([b3ea698](https://github.com/angular/angular/commit/b3ea698)), closes [#28452](https://github.com/angular/angular/issues/28452)
|
||||
|
||||
|
||||
|
||||
<a name="8.2.4"></a>
|
||||
## [8.2.4](https://github.com/angular/angular/compare/8.2.3...8.2.4) (2019-08-28)
|
||||
|
||||
This release contains various API docs improvements.
|
||||
|
||||
|
||||
|
||||
<a name="8.2.3"></a>
|
||||
## [8.2.3](https://github.com/angular/angular/compare/8.2.2...8.2.3) (2019-08-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bazel:** pin `[@microsoft](https://github.com/microsoft)/api-extractor` ([#32187](https://github.com/angular/angular/issues/32187)) ([a7b9478](https://github.com/angular/angular/commit/a7b9478))
|
||||
|
||||
|
||||
|
||||
<a name="8.2.2"></a>
|
||||
## [8.2.2](https://github.com/angular/angular/compare/8.2.1...8.2.2) (2019-08-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bazel:** disable treeshaking when generating FESM and UMD bundles ([#32069](https://github.com/angular/angular/issues/32069)) ([3420d29](https://github.com/angular/angular/commit/3420d29))
|
||||
|
||||
|
||||
<a name="8.2.1"></a>
|
||||
## [8.2.1](https://github.com/angular/angular/compare/8.2.0...8.2.1) (2019-08-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **upgrade:** compile downgraded components synchronously (if possible) ([#31840](https://github.com/angular/angular/issues/31840)) ([04ebd59](https://github.com/angular/angular/commit/04ebd59)), closes [#27217](https://github.com/angular/angular/issues/27217) [#30330](https://github.com/angular/angular/issues/30330)
|
||||
|
||||
|
||||
|
||||
<a name="8.2.0"></a>
|
||||
# [8.2.0](https://github.com/angular/angular/compare/8.2.0-rc.0...8.2.0) (2019-07-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** DebugElement.listeners not cleared on destroy ([#31820](https://github.com/angular/angular/issues/31820)) ([46b160e](https://github.com/angular/angular/commit/46b160e))
|
||||
|
||||
|
||||
|
||||
<a name="8.2.0-rc.0"></a>
|
||||
# [8.2.0-rc.0](https://github.com/angular/angular/compare/8.2.0-next.2...8.2.0-rc.0) (2019-07-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bazel:** increase memory limit of ngc under bazel from 2 to 4 GB ([#31784](https://github.com/angular/angular/issues/31784)) ([5a8eb92](https://github.com/angular/angular/commit/5a8eb92))
|
||||
* **core:** allow Z variations of CSS transforms in sanitizer ([#29264](https://github.com/angular/angular/issues/29264)) ([78e7fdd](https://github.com/angular/angular/commit/78e7fdd))
|
||||
* **elements:** handle falsy initial value ([#31604](https://github.com/angular/angular/issues/31604)) ([7151eae](https://github.com/angular/angular/commit/7151eae)), closes [angular/angular#30834](https://github.com/angular/angular/issues/30834)
|
||||
* **platform-browser:** debug element query predicates not compatible with strictFunctionTypes ([#30993](https://github.com/angular/angular/issues/30993)) ([10a1e19](https://github.com/angular/angular/commit/10a1e19))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **bazel:** compile targets used for indexing by Kythe with Ivy ([#31786](https://github.com/angular/angular/issues/31786)) ([82055b2](https://github.com/angular/angular/commit/82055b2))
|
||||
* **upgrade:** support $element in upgraded component template/templateUrl functions ([#31637](https://github.com/angular/angular/issues/31637)) ([29e1c53](https://github.com/angular/angular/commit/29e1c53))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **compiler:** avoid copying from prototype while cloning an object ([#31638](https://github.com/angular/angular/issues/31638)) ([24ca582](https://github.com/angular/angular/commit/24ca582)), closes [#31627](https://github.com/angular/angular/issues/31627)
|
||||
|
||||
|
||||
|
||||
<a name="8.1.3"></a>
|
||||
## [8.1.3](https://github.com/angular/angular/compare/8.1.2...8.1.3) (2019-07-30)
|
||||
## [8.1.3](https://github.com/angular/angular/compare/8.1.2...8.1.3) (2019-07-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
@ -12,6 +92,18 @@
|
||||
* **compiler:** avoid copying from prototype while cloning an object ([#31638](https://github.com/angular/angular/issues/31638)) ([1f3daa0](https://github.com/angular/angular/commit/1f3daa0)), closes [#31627](https://github.com/angular/angular/issues/31627)
|
||||
|
||||
|
||||
<a name="8.2.0-next.2"></a>
|
||||
# [8.2.0-next.2](https://github.com/angular/angular/compare/8.2.0-next.1...8.2.0-next.2) (2019-07-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* use the correct WTF array to iterate over ([#31208](https://github.com/angular/angular/issues/31208)) ([9204de9](https://github.com/angular/angular/commit/9204de9))
|
||||
* **bazel:** pass custom bazel compiler host rather than rewriting one ([#31496](https://github.com/angular/angular/issues/31496)) ([0c61a35](https://github.com/angular/angular/commit/0c61a35))
|
||||
* **compiler-cli:** Return original sourceFile instead of redirected sourceFile from getSourceFile ([#26036](https://github.com/angular/angular/issues/26036)) ([3166cff](https://github.com/angular/angular/commit/3166cff)), closes [#22524](https://github.com/angular/angular/issues/22524)
|
||||
* **language-service:** Eagarly initialize data members ([#31577](https://github.com/angular/angular/issues/31577)) ([0110de2](https://github.com/angular/angular/commit/0110de2))
|
||||
|
||||
|
||||
|
||||
<a name="8.1.2"></a>
|
||||
## [8.1.2](https://github.com/angular/angular/compare/8.1.0...8.1.2) (2019-07-17)
|
||||
@ -25,6 +117,22 @@
|
||||
|
||||
|
||||
|
||||
<a name="8.2.0-next.1"></a>
|
||||
# [8.2.0-next.1](https://github.com/angular/angular/compare/8.2.0-next.0...8.2.0-next.1) (2019-07-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bazel:** revert location of xi18n outputs to bazel-genfiles ([#31410](https://github.com/angular/angular/issues/31410)) ([1d3e227](https://github.com/angular/angular/commit/1d3e227))
|
||||
* **compiler:** give ASTWithSource its own visit method ([#31347](https://github.com/angular/angular/issues/31347)) ([6aaca21](https://github.com/angular/angular/commit/6aaca21))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **core:** add automatic migration from Renderer to Renderer2 ([#30936](https://github.com/angular/angular/issues/30936)) ([c095597](https://github.com/angular/angular/commit/c095597))
|
||||
|
||||
|
||||
|
||||
<a name="8.1.1"></a>
|
||||
## [8.1.1](https://github.com/angular/angular/compare/8.1.0...8.1.1) (2019-07-10)
|
||||
|
||||
@ -34,6 +142,23 @@
|
||||
* **core:** export provider interfaces that are part of the public API types ([#31377](https://github.com/angular/angular/issues/31377)) ([bebf089](https://github.com/angular/angular/commit/bebf089)), closes [/github.com/angular/angular/pull/31377#discussion_r299254408](https://github.com//github.com/angular/angular/pull/31377/issues/discussion_r299254408) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L365-L366](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L365-L366) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L283-L284](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L283-L284) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts#L23](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts/issues/L23)
|
||||
|
||||
|
||||
<a name="8.2.0-next.0"></a>
|
||||
# [8.2.0-next.0](https://github.com/angular/angular/compare/8.1.0-rc.0...8.2.0-next.0) (2019-07-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** handle `undefined` meta in `injectArgs` ([#31333](https://github.com/angular/angular/issues/31333)) ([80ccd6c](https://github.com/angular/angular/commit/80ccd6c)), closes [CLI #14888](https://github.com/angular/angular-cli/issues/14888)
|
||||
* **service-worker:** cache opaque responses in data groups with `freshness` strategy ([#30977](https://github.com/angular/angular/issues/30977)) ([d7be38f](https://github.com/angular/angular/commit/d7be38f)), closes [#30968](https://github.com/angular/angular/issues/30968)
|
||||
* **service-worker:** cache opaque responses when requests exceeds timeout threshold ([#30977](https://github.com/angular/angular/issues/30977)) ([93abc35](https://github.com/angular/angular/commit/93abc35))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **bazel:** allow passing a custom bazel compiler host to ngc compile ([#31341](https://github.com/angular/angular/issues/31341)) ([a29dc96](https://github.com/angular/angular/commit/a29dc96))
|
||||
* **bazel:** allow passing and rewriting an old bazel host ([#31381](https://github.com/angular/angular/issues/31381)) ([11a208f](https://github.com/angular/angular/commit/11a208f)), closes [#31341](https://github.com/angular/angular/issues/31341)
|
||||
|
||||
|
||||
|
||||
<a name="8.1.0"></a>
|
||||
# [8.1.0](https://github.com/angular/angular/compare/8.1.0-rc.0...8.1.0) (2019-07-02)
|
||||
|
@ -233,6 +233,7 @@ There are currently a few exceptions to the "use package name" rule:
|
||||
* **docs-infra**: used for docs-app (angular.io) related changes within the /aio directory of the
|
||||
repo
|
||||
* **ivy**: used for changes to the [Ivy renderer](https://github.com/angular/angular/issues/21706).
|
||||
* **ngcc**: used for changes to the [Angular Compatibility Compiler](./packages/compiler-cli/ngcc/README.md)
|
||||
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all
|
||||
packages (e.g. `style: add missing semicolons`) and for docs changes that are not related to a
|
||||
specific package (e.g. `docs: fix typo in tutorial`).
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
# Angular
|
||||
|
||||
Angular is a development platform for building mobile and desktop web applications using Typescript/JavaScript and other languages.
|
||||
Angular is a development platform for building mobile and desktop web applications using TypeScript/JavaScript and other languages.
|
||||
|
||||
## Quickstart
|
||||
|
||||
@ -14,7 +14,7 @@ Angular is a development platform for building mobile and desktop web applicatio
|
||||
|
||||
## Changelog
|
||||
|
||||
[Learn about the latest improvements][changelog].
|
||||
[Learn about the latest improvements][changelog].
|
||||
|
||||
## Want to help?
|
||||
|
||||
|
17
WORKSPACE
17
WORKSPACE
@ -21,8 +21,8 @@ http_archive(
|
||||
patch_args = ["-p1"],
|
||||
# Patch https://github.com/bazelbuild/rules_nodejs/pull/903
|
||||
patches = ["//tools:rollup_bundle_commonjs_ignoreGlobal.patch"],
|
||||
sha256 = "6d4edbf28ff6720aedf5f97f9b9a7679401bf7fca9d14a0fff80f644a99992b4",
|
||||
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.32.2/rules_nodejs-0.32.2.tar.gz"],
|
||||
sha256 = "7c4a690268be97c96f04d505224ec4cb1ae53c2c2b68be495c9bd2634296a5cd",
|
||||
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.34.0/rules_nodejs-0.34.0.tar.gz"],
|
||||
)
|
||||
|
||||
# Check the bazel version and download npm dependencies
|
||||
@ -53,7 +53,8 @@ Try running `yarn bazel` instead.
|
||||
# - 0.32.0 yarn_install and npm_install no longer puts build files under symlinked node_modules
|
||||
# - 0.32.1 remove override of @bazel/tsetse & exclude typescript lib declarations in node_module_library transitive_declarations
|
||||
# - 0.32.2 resolves bug in @bazel/hide-bazel-files postinstall step
|
||||
check_rules_nodejs_version(minimum_version_string = "0.32.2")
|
||||
# - 0.34.0 introduces protractor rule
|
||||
check_rules_nodejs_version(minimum_version_string = "0.34.0")
|
||||
|
||||
# Setup the Node.js toolchain
|
||||
node_repositories(
|
||||
@ -64,6 +65,9 @@ node_repositories(
|
||||
},
|
||||
node_version = "10.16.0",
|
||||
package_json = ["//:package.json"],
|
||||
yarn_repositories = {
|
||||
"1.17.3": ("yarn-v1.17.3.tar.gz", "yarn-v1.17.3", "e3835194409f1b3afa1c62ca82f561f1c29d26580c9e220c36866317e043c6f3"),
|
||||
},
|
||||
# yarn 1.13.0 under Bazel has a regression on Windows that causes build errors on rebuilds:
|
||||
# ```
|
||||
# ERROR: Source forest creation failed: C:/.../fyuc5c3n/execroot/angular/external (Directory not empty)
|
||||
@ -72,7 +76,7 @@ node_repositories(
|
||||
# It possible that versions of yarn past 1.13.0 do not have this issue, however, before
|
||||
# advancing this version we need to test manually on Windows that the above error does not
|
||||
# happen as the issue is not caught by CI.
|
||||
yarn_version = "1.12.1",
|
||||
yarn_version = "1.17.3",
|
||||
)
|
||||
|
||||
yarn_install(
|
||||
@ -91,6 +95,11 @@ load("//packages/bazel:package.bzl", "rules_angular_dev_dependencies")
|
||||
|
||||
rules_angular_dev_dependencies()
|
||||
|
||||
# Load protractor dependencies
|
||||
load("@npm_bazel_protractor//:package.bzl", "npm_bazel_protractor_dependencies")
|
||||
|
||||
npm_bazel_protractor_dependencies()
|
||||
|
||||
# Load karma dependencies
|
||||
load("@npm_bazel_karma//:package.bzl", "rules_karma_dependencies")
|
||||
|
||||
|
@ -14,10 +14,12 @@ Here are the most important tasks you might need to use:
|
||||
|
||||
* `yarn` - install all the dependencies.
|
||||
* `yarn setup` - install all the dependencies, boilerplate, stackblitz, zips and run dgeni on the docs.
|
||||
* `yarn setup-local` - same as `setup`, but use the locally built Angular packages for aio and docs examples boilerplate.
|
||||
* `yarn setup-local` - same as `setup`, but build the Angular packages from the source code and use these locally built versions (instead of the ones fetched from npm) for aio and docs examples boilerplate.
|
||||
|
||||
* `yarn build` - create a production build of the application (after installing dependencies, boilerplate, etc).
|
||||
* `yarn build-local` - same as `build`, but use `setup-local` instead of `setup`.
|
||||
* `yarn build-with-ivy` - same as `build-local`, but in addition also turns on `ivy` mode in aio.
|
||||
(Note: To turn on `ivy` mode in examples, see `yarn boilerplate:add` below.)
|
||||
|
||||
* `yarn start` - run a development web server that watches the files; then builds the doc-viewer and reloads the page, as necessary.
|
||||
* `yarn serve-and-sync` - run both the `docs-watch` and `start` in the same console.
|
||||
@ -31,7 +33,10 @@ Here are the most important tasks you might need to use:
|
||||
* `yarn docs-lint` - check that the doc gen code follows our style rules.
|
||||
* `yarn docs-test` - run the unit tests for the doc generation code.
|
||||
|
||||
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally. Add the option `--local` to use your local version of Angular contained in the "dist" folder.
|
||||
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally.
|
||||
- Add the option `--local` to use your local version of Angular contained in the "dist" folder.
|
||||
- Add the option `--ivy` to turn on `ivy` mode.
|
||||
|
||||
* `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`.
|
||||
* `yarn generate-stackblitz` - generate the stackblitz files that are used by the `live-example` tags in the docs.
|
||||
* `yarn generate-zips` - generate the zip files from the examples. Zip available via the `live-example` tags in the docs.
|
||||
@ -41,6 +46,15 @@ Here are the most important tasks you might need to use:
|
||||
- `yarn example-e2e --filter=foo` - limit e2e tests to those containing the word "foo"
|
||||
- `yarn example-e2e --setup --local` - run e2e tests with the local version of Angular contained in the "dist" folder
|
||||
|
||||
> **Note for Windows users**
|
||||
>
|
||||
> Setting up the examples involves creating some [symbolic links](https://en.wikipedia.org/wiki/Symbolic_link) (see [here](./tools/examples/README.md#symlinked-node_modules) for details). On Windows, this requires to either have [Developer Mode enabled](https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10) (supported on Windows 10 or newer) or run the setup commands as administrator.
|
||||
>
|
||||
> The affected commands are:
|
||||
> - `yarn setup` / `yarn setup-*`
|
||||
> - `yarn build` / `yarn build-*`
|
||||
> - `yarn boilerplate:add`
|
||||
> - `yarn example-e2e --setup`
|
||||
|
||||
## Using ServiceWorker locally
|
||||
|
||||
|
@ -7,7 +7,7 @@ The Angular CLI is a command-line interface tool that you use to initialize, dev
|
||||
Major versions of Angular CLI follow the supported major version of Angular, but minor versions can be released separately.
|
||||
|
||||
Install the CLI using the `npm` package manager:
|
||||
<code-example format="." language="bash">
|
||||
<code-example language="bash">
|
||||
npm install -g @angular/cli
|
||||
</code-example>
|
||||
|
||||
@ -20,14 +20,14 @@ Invoke the tool on the command line through the `ng` executable.
|
||||
Online help is available on the command line.
|
||||
Enter the following to list commands or options for a given command (such as [generate](cli/generate)) with a short description.
|
||||
|
||||
<code-example format="." language="bash">
|
||||
<code-example language="bash">
|
||||
ng help
|
||||
ng generate --help
|
||||
</code-example>
|
||||
|
||||
To create, build, and serve a new, basic Angular project on a development server, go to the parent directory of your new workspace use the following commands:
|
||||
|
||||
<code-example format="." language="bash">
|
||||
<code-example language="bash">
|
||||
ng new my-first-project
|
||||
cd my-first-project
|
||||
ng serve
|
||||
@ -83,7 +83,7 @@ Command syntax is shown as follows:
|
||||
Option aliases are prefixed with a single dash (-).
|
||||
Arguments are not prefixed.
|
||||
For example:
|
||||
<code-example format="." language="bash">
|
||||
<code-example language="bash">
|
||||
ng build my-app -c production
|
||||
</code-example>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// #docplaster
|
||||
// #docregion imports
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { CartService } from '../cart.service';
|
||||
// #enddocregion imports
|
||||
|
||||
@ -10,12 +10,14 @@ import { CartService } from '../cart.service';
|
||||
styleUrls: ['./cart.component.css']
|
||||
})
|
||||
// #docregion props-services, submit
|
||||
export class CartComponent {
|
||||
export class CartComponent implements OnInit {
|
||||
items;
|
||||
|
||||
constructor(
|
||||
private cartService: CartService
|
||||
) {
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.items = this.cartService.getItems();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// #docplaster
|
||||
// #docregion imports
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { CartService } from '../cart.service';
|
||||
// #enddocregion
|
||||
@ -11,7 +11,7 @@ import { CartService } from '../cart.service';
|
||||
styleUrls: ['./shipping.component.css']
|
||||
})
|
||||
// #docregion props, ctor
|
||||
export class ShippingComponent {
|
||||
export class ShippingComponent implements OnInit {
|
||||
shippingCosts;
|
||||
// #enddocregion props
|
||||
|
||||
@ -19,10 +19,12 @@ export class ShippingComponent {
|
||||
constructor(
|
||||
private cartService: CartService
|
||||
) {
|
||||
// #enddocregion inject-cart-service
|
||||
this.shippingCosts = this.cartService.getShippingPrices();
|
||||
// #docregion inject-cart-service
|
||||
}
|
||||
// #enddocregion inject-cart-service
|
||||
|
||||
ngOnInit() {
|
||||
this.shippingCosts = this.cartService.getShippingPrices();
|
||||
}
|
||||
|
||||
// #docregion props
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<h1>HTTP Sample</h1>
|
||||
<div>
|
||||
<input type="checkbox" id="heroes" [checked]="toggleHeroes" (click)="toggleHeroes()">
|
||||
<input type="checkbox" id="heroes" [checked]="showHeroes" (click)="toggleHeroes()">
|
||||
<label for="heroes">Heroes</label>
|
||||
|
||||
<input type="checkbox" id="config" [checked]="showConfig" (click)="toggleConfig()">
|
||||
|
@ -12,7 +12,7 @@ if (environment.production) {
|
||||
// use the require method provided by webpack
|
||||
declare const require;
|
||||
// we use the webpack raw-loader to return the content as a string
|
||||
const translations = require(`raw-loader!./locale/messages.fr.xlf`);
|
||||
const translations = require('raw-loader!./locale/messages.fr.xlf').default;
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule, {
|
||||
providers: [
|
||||
|
@ -0,0 +1,24 @@
|
||||
import { browser, element, by } from 'protractor';
|
||||
import { logging } from 'selenium-webdriver';
|
||||
|
||||
describe('Providers and ViewProviders', function () {
|
||||
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
it('shows basic flower emoji', function() {
|
||||
expect(element.all(by.css('p')).get(0).getText()).toContain('🌺');
|
||||
});
|
||||
|
||||
it('shows whale emoji', function() {
|
||||
expect(element.all(by.css('p')).get(1).getText()).toContain('🐳');
|
||||
});
|
||||
|
||||
it('shows sunflower from FlowerService', function() {
|
||||
expect(element.all(by.css('p')).get(8).getText()).toContain('🌻');
|
||||
});
|
||||
|
||||
});
|
||||
|
10
aio/content/examples/providers-viewproviders/src/app/animal.service.ts
Executable file
10
aio/content/examples/providers-viewproviders/src/app/animal.service.ts
Executable file
@ -0,0 +1,10 @@
|
||||
// #docregion animal-service
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AnimalService {
|
||||
emoji = '🐳';
|
||||
}
|
||||
// #enddocregion animal-service
|
@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FlowerService } from './flower.service';
|
||||
import { AnimalService } from './animal.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: [ './app.component.css' ]
|
||||
})
|
||||
// #docregion injection
|
||||
export class AppComponent {
|
||||
constructor(public flower: FlowerService) {}
|
||||
}
|
||||
// #enddocregion injection
|
15
aio/content/examples/providers-viewproviders/src/app/app.component.html
Executable file
15
aio/content/examples/providers-viewproviders/src/app/app.component.html
Executable file
@ -0,0 +1,15 @@
|
||||
|
||||
<h2>From AppComponent:</h2>
|
||||
<!-- #docregion binding-flower -->
|
||||
<p>Emoji from FlowerService: {{flower.emoji}}</p>
|
||||
<!-- #enddocregion binding-flower -->
|
||||
<!-- #docregion binding-animal -->
|
||||
<p>Emoji from AnimalService: {{animal.emoji}}</p>
|
||||
<!-- #enddocregion binding-animal -->
|
||||
|
||||
<hr />
|
||||
|
||||
<h2>From ChildComponent:</h2>
|
||||
<!-- #docregion content-projection -->
|
||||
<app-child><app-inspector></app-inspector></app-child>
|
||||
<!-- #enddocregion content-projection -->
|
15
aio/content/examples/providers-viewproviders/src/app/app.component.ts
Executable file
15
aio/content/examples/providers-viewproviders/src/app/app.component.ts
Executable file
@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FlowerService } from './flower.service';
|
||||
import { AnimalService } from './animal.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: [ './app.component.css' ]
|
||||
})
|
||||
// #docregion inject-animal-service
|
||||
export class AppComponent {
|
||||
constructor(public flower: FlowerService, public animal: AnimalService) {}
|
||||
}
|
||||
// #enddocregion inject-animal-service
|
17
aio/content/examples/providers-viewproviders/src/app/app.module.ts
Executable file
17
aio/content/examples/providers-viewproviders/src/app/app.module.ts
Executable file
@ -0,0 +1,17 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { ChildComponent } from './child/child.component';
|
||||
import { InspectorComponent } from './inspector/inspector.component';
|
||||
|
||||
// #docregion appmodule
|
||||
@NgModule({
|
||||
imports: [ BrowserModule, FormsModule ],
|
||||
declarations: [ AppComponent, ChildComponent, InspectorComponent ],
|
||||
bootstrap: [ AppComponent ],
|
||||
providers: []
|
||||
})
|
||||
export class AppModule { }
|
||||
// #enddocregion appmodule
|
@ -0,0 +1,19 @@
|
||||
import { Component, OnInit, Host, SkipSelf, Optional } from '@angular/core';
|
||||
import { FlowerService } from '../flower.service';
|
||||
|
||||
// #docregion flowerservice
|
||||
@Component({
|
||||
selector: 'app-child',
|
||||
templateUrl: './child.component.html',
|
||||
styleUrls: ['./child.component.css'],
|
||||
// use the providers array to provide a service
|
||||
providers: [{ provide: FlowerService, useValue: { emoji: '🌻' } }]
|
||||
})
|
||||
|
||||
export class ChildComponent {
|
||||
// inject the service
|
||||
constructor( public flower: FlowerService) { }
|
||||
}
|
||||
|
||||
// #enddocregion flowerservice
|
||||
|
@ -0,0 +1,4 @@
|
||||
.container {
|
||||
border: 1px solid darkblue;
|
||||
padding: 1rem;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<!-- #docplaster -->
|
||||
<!-- #docregion child-component -->
|
||||
<!-- #docregion flower-binding -->
|
||||
<p>Emoji from FlowerService: {{flower.emoji}}</p>
|
||||
<!-- #enddocregion flower-binding -->
|
||||
<!-- #docregion animal-binding -->
|
||||
<p>Emoji from AnimalService: {{animal.emoji}}</p>
|
||||
<!-- #enddocregion animal-binding -->
|
||||
|
||||
<div class="container">
|
||||
<h3>Content projection</h3>
|
||||
<!-- #enddocregion child-component -->
|
||||
<p>The following is coming from content. It doesn't get to see the puppy because the puppy is declared inside the view only.</p>
|
||||
<!-- #docregion child-component -->
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
|
||||
<h3>Inside the view</h3>
|
||||
<!-- #enddocregion child-component -->
|
||||
<p>The following is inside the view so it does see the puppy.</p>
|
||||
<!-- #docregion child-component -->
|
||||
<app-inspector></app-inspector>
|
||||
<!-- #enddocregion child-component -->
|
||||
|
@ -0,0 +1,44 @@
|
||||
// #docplaster
|
||||
import { Component, OnInit, Host, SkipSelf, Optional } from '@angular/core';
|
||||
import { FlowerService } from '../flower.service';
|
||||
import { AnimalService } from '../animal.service';
|
||||
|
||||
// #docregion provide-animal-service
|
||||
@Component({
|
||||
selector: 'app-child',
|
||||
templateUrl: './child.component.html',
|
||||
styleUrls: ['./child.component.css'],
|
||||
// provide services
|
||||
providers: [{ provide: FlowerService, useValue: { emoji: '🌻' } }],
|
||||
viewProviders: [{ provide: AnimalService, useValue: { emoji: '🐶' } }]
|
||||
})
|
||||
|
||||
export class ChildComponent {
|
||||
// inject service
|
||||
constructor( public flower: FlowerService, public animal: AnimalService) { }
|
||||
// #enddocregion provide-animal-service
|
||||
|
||||
// viewProviders ensures that only the view gets to see this.
|
||||
// With the AnimalService in the viewProviders, the
|
||||
// InspectorComponent doesn't get to see it because the
|
||||
// inspector is in the content.
|
||||
|
||||
|
||||
// constructor( public flower: FlowerService, @Optional() @Host() public animal: AnimalService) { }
|
||||
|
||||
// Comment out the above constructor and alternately
|
||||
// uncomment the two following constructors to see the
|
||||
// effects of @Host() and @Host() + @SkipSelf().
|
||||
|
||||
// constructor(
|
||||
// @Host() public animal : AnimalService,
|
||||
// @Host() @Optional() public flower : FlowerService) { }
|
||||
|
||||
// constructor(
|
||||
// @SkipSelf() @Host() public animal : AnimalService,
|
||||
// @SkipSelf() @Host() @Optional() public flower : FlowerService) { }
|
||||
|
||||
// #docregion provide-animal-service
|
||||
}
|
||||
// #enddocregion provide-animal-service
|
||||
|
11
aio/content/examples/providers-viewproviders/src/app/flower.service.ts
Executable file
11
aio/content/examples/providers-viewproviders/src/app/flower.service.ts
Executable file
@ -0,0 +1,11 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
// #docregion flowerservice
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class FlowerService {
|
||||
emoji = '🌺';
|
||||
}
|
||||
// #enddocregion flowerservice
|
||||
|
@ -0,0 +1,4 @@
|
||||
<!-- #docregion binding -->
|
||||
<p>Emoji from FlowerService: {{flower.emoji}}</p>
|
||||
<p>Emoji from AnimalService: {{animal.emoji}}</p>
|
||||
<!-- #enddocregion binding -->
|
@ -0,0 +1,14 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FlowerService } from '../flower.service';
|
||||
import { AnimalService } from '../animal.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-inspector',
|
||||
templateUrl: './inspector.component.html',
|
||||
styleUrls: ['./inspector.component.css']
|
||||
})
|
||||
// #docregion injection
|
||||
export class InspectorComponent {
|
||||
constructor(public flower: FlowerService, public animal: AnimalService) { }
|
||||
}
|
||||
// #enddocregion injection
|
14
aio/content/examples/providers-viewproviders/src/index.html
Normal file
14
aio/content/examples/providers-viewproviders/src/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>providers vs. viewProviders</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
12
aio/content/examples/providers-viewproviders/src/main.ts
Normal file
12
aio/content/examples/providers-viewproviders/src/main.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.log(err));
|
10
aio/content/examples/providers-viewproviders/stackblitz.json
Normal file
10
aio/content/examples/providers-viewproviders/stackblitz.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description": "Inputs and Outputs",
|
||||
"files": [
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js",
|
||||
"!**/*.[1,2].*"
|
||||
],
|
||||
"file": "src/app/app.component.ts",
|
||||
"tags": ["Inputs and Outputs"]
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
import { browser, element, by } from 'protractor';
|
||||
|
||||
describe('Resolution-modifiers-example', function () {
|
||||
|
||||
beforeAll(function () {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
it('shows basic flower emoji', function() {
|
||||
expect(element.all(by.css('p')).get(0).getText()).toContain('🌸');
|
||||
});
|
||||
|
||||
it('shows basic leaf emoji', function() {
|
||||
expect(element.all(by.css('p')).get(1).getText()).toContain('🌿');
|
||||
});
|
||||
|
||||
it('shows yellow flower in host child', function() {
|
||||
expect(element.all(by.css('p')).get(9).getText()).toContain('🌼');
|
||||
});
|
||||
|
||||
});
|
0
aio/content/examples/resolution-modifiers/src/app/app.component.css
Executable file
0
aio/content/examples/resolution-modifiers/src/app/app.component.css
Executable file
14
aio/content/examples/resolution-modifiers/src/app/app.component.html
Executable file
14
aio/content/examples/resolution-modifiers/src/app/app.component.html
Executable file
@ -0,0 +1,14 @@
|
||||
<h1>DI resolution modifiers</h1>
|
||||
|
||||
<p>Basic flower service: {{flower.emoji}}</p>
|
||||
<p>Basic leaf service: {{leaf.emoji}}</p>
|
||||
|
||||
<app-optional></app-optional>
|
||||
|
||||
<app-self></app-self>
|
||||
|
||||
<app-self-no-data></app-self-no-data>
|
||||
|
||||
<app-skipself></app-skipself>
|
||||
|
||||
<app-host-parent></app-host-parent>
|
13
aio/content/examples/resolution-modifiers/src/app/app.component.ts
Executable file
13
aio/content/examples/resolution-modifiers/src/app/app.component.ts
Executable file
@ -0,0 +1,13 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { LeafService } from './leaf.service';
|
||||
import { FlowerService } from './flower.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: [ './app.component.css' ]
|
||||
})
|
||||
export class AppComponent {
|
||||
name = 'Angular';
|
||||
constructor(public flower: FlowerService, public leaf: LeafService) {}
|
||||
}
|
33
aio/content/examples/resolution-modifiers/src/app/app.module.ts
Executable file
33
aio/content/examples/resolution-modifiers/src/app/app.module.ts
Executable file
@ -0,0 +1,33 @@
|
||||
;
|
||||
import { OptionalComponent } from './optional/optional.component';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { SelfNoDataComponent } from './self-no-data/self-no-data.component';
|
||||
import { HostComponent } from './host/host.component';
|
||||
import { SelfComponent } from './self/self.component';
|
||||
import { SkipselfComponent } from './skipself/skipself.component';
|
||||
import { HostParentComponent } from './host-parent/host-parent.component';
|
||||
import { HostChildComponent } from './host-child/host-child.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
FormsModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
OptionalComponent,
|
||||
SelfComponent,
|
||||
SelfNoDataComponent,
|
||||
HostComponent,
|
||||
SkipselfComponent,
|
||||
HostParentComponent,
|
||||
HostChildComponent
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
providers: []
|
||||
})
|
||||
export class AppModule { }
|
9
aio/content/examples/resolution-modifiers/src/app/flower.service.ts
Executable file
9
aio/content/examples/resolution-modifiers/src/app/flower.service.ts
Executable file
@ -0,0 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root' // provide this service in the root ModuleInjector
|
||||
|
||||
})
|
||||
export class FlowerService {
|
||||
emoji = '🌸';
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
.section {
|
||||
border: 2px solid #369;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<div class="section">
|
||||
<h2>Child of @Host() Component</h2>
|
||||
<p>Flower emoji: {{flower.emoji}}</p>
|
||||
</div>
|
@ -0,0 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FlowerService } from '../flower.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-host-child',
|
||||
templateUrl: './host-child.component.html',
|
||||
styleUrls: ['./host-child.component.css']
|
||||
})
|
||||
export class HostChildComponent {
|
||||
constructor(public flower: FlowerService) { }
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
.section {
|
||||
border: 2px solid #369;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<div class="section">
|
||||
<h2>Parent of @Host() Component</h2>
|
||||
<p>Flower emoji: {{flower.emoji}}</p>
|
||||
<app-host></app-host>
|
||||
</div>
|
@ -0,0 +1,16 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FlowerService } from '../flower.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-host-parent',
|
||||
templateUrl: './host-parent.component.html',
|
||||
styleUrls: ['./host-parent.component.css'],
|
||||
providers: [{ provide: FlowerService, useValue: { emoji: '🌺' } }]
|
||||
|
||||
})
|
||||
export class HostParentComponent {
|
||||
|
||||
constructor(public flower: FlowerService) { }
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
.section {
|
||||
border: 2px solid #369;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<div class="section">
|
||||
<h2>@Host() Component</h2>
|
||||
<p>Flower emoji: {{flower.emoji}}</p>
|
||||
<p><i>(@Host() stops it here)</i></p>
|
||||
<app-host-child></app-host-child>
|
||||
</div>
|
21
aio/content/examples/resolution-modifiers/src/app/host/host.component.ts
Executable file
21
aio/content/examples/resolution-modifiers/src/app/host/host.component.ts
Executable file
@ -0,0 +1,21 @@
|
||||
import { Component, Host, Optional } from '@angular/core';
|
||||
import { FlowerService } from '../flower.service';
|
||||
|
||||
// #docregion host-component
|
||||
@Component({
|
||||
selector: 'app-host',
|
||||
templateUrl: './host.component.html',
|
||||
styleUrls: ['./host.component.css'],
|
||||
// provide the service
|
||||
providers: [{ provide: FlowerService, useValue: { emoji: '🌼' } }]
|
||||
})
|
||||
export class HostComponent {
|
||||
// use @Host() in the constructor when injecting the service
|
||||
constructor(@Host() @Optional() public flower: FlowerService) { }
|
||||
|
||||
}
|
||||
// #enddocregion host-component
|
||||
|
||||
// if you take out @Host() and the providers array, flower will be red hibiscus
|
||||
|
||||
|
11
aio/content/examples/resolution-modifiers/src/app/leaf.service.ts
Executable file
11
aio/content/examples/resolution-modifiers/src/app/leaf.service.ts
Executable file
@ -0,0 +1,11 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
// #docregion leafservice
|
||||
export class LeafService {
|
||||
emoji = '🌿';
|
||||
}
|
||||
// #enddocregion leafservice
|
||||
|
7
aio/content/examples/resolution-modifiers/src/app/optional.service.ts
Executable file
7
aio/content/examples/resolution-modifiers/src/app/optional.service.ts
Executable file
@ -0,0 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class OptionalService {
|
||||
}
|
||||
|
||||
// This service isn't provided anywhere.
|
@ -0,0 +1,5 @@
|
||||
.section {
|
||||
border: 2px solid #369;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<div class="section">
|
||||
<h2>@Optional() Component</h2>
|
||||
<p>This component still works even though the OptionalService (notice @Optional() in the consturctor isn't provided or configured anywhere. Angular goes through tree and visibilty rules, and if it doesn't find the requested service, returns null.</p>
|
||||
</div>
|
@ -0,0 +1,21 @@
|
||||
import { Component, Optional } from '@angular/core';
|
||||
import { OptionalService } from '../optional.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-optional',
|
||||
templateUrl: './optional.component.html',
|
||||
styleUrls: ['./optional.component.css']
|
||||
})
|
||||
|
||||
// #docregion optional-component
|
||||
export class OptionalComponent {
|
||||
constructor(@Optional() public optional: OptionalService) {}
|
||||
}
|
||||
// #enddocregion optional-component
|
||||
|
||||
// The OptionalService isn't provided here, in the @Injectable()
|
||||
// providers array, or in the NgModule. If you remove @Optional()
|
||||
// from the constructor, you'll get an error.
|
||||
|
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
.section {
|
||||
border: 2px solid #369;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<div class="section">
|
||||
<h2>@Self() Component (without a provider)</h2>
|
||||
<p>Leaf emoji: {{leaf?.emoji}}</p>
|
||||
</div>
|
@ -0,0 +1,18 @@
|
||||
import { Component, Self, Optional } from '@angular/core';
|
||||
import { LeafService } from '../leaf.service';
|
||||
|
||||
// #docregion self-no-data-component
|
||||
@Component({
|
||||
selector: 'app-self-no-data',
|
||||
templateUrl: './self-no-data.component.html',
|
||||
styleUrls: ['./self-no-data.component.css']
|
||||
})
|
||||
export class SelfNoDataComponent {
|
||||
constructor(@Self() @Optional() public leaf: LeafService) { }
|
||||
}
|
||||
|
||||
// #enddocregion self-no-data-component
|
||||
|
||||
// The app doesn't break because the value being available at self is optional.
|
||||
// If you remove @Optional(), the app breaks.
|
||||
|
@ -0,0 +1,5 @@
|
||||
.section {
|
||||
border: 2px solid #369;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<div class="section">
|
||||
<h2>@Self() Component</h2>
|
||||
<p>Flower emoji: {{flower?.emoji}}</p>
|
||||
</div>
|
19
aio/content/examples/resolution-modifiers/src/app/self/self.component.ts
Executable file
19
aio/content/examples/resolution-modifiers/src/app/self/self.component.ts
Executable file
@ -0,0 +1,19 @@
|
||||
import { Component, Self } from '@angular/core';
|
||||
import { FlowerService } from '../flower.service';
|
||||
|
||||
// #docregion self-component
|
||||
@Component({
|
||||
selector: 'app-self',
|
||||
templateUrl: './self.component.html',
|
||||
styleUrls: ['./self.component.css'],
|
||||
providers: [{ provide: FlowerService, useValue: { emoji: '🌼' } }]
|
||||
|
||||
})
|
||||
export class SelfComponent {
|
||||
constructor(@Self() public flower: FlowerService) {}
|
||||
}
|
||||
// #enddocregion self-component
|
||||
|
||||
// This component provides the FlowerService so the injector
|
||||
// doesn't have to look further up the injector tree
|
||||
|
@ -0,0 +1,5 @@
|
||||
.section {
|
||||
border: 2px solid #369;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<div class="section">
|
||||
<h2>@SkipSelf() Component</h2>
|
||||
<p>Leaf emoji: {{leaf.emoji}}</p>
|
||||
</div>
|
@ -0,0 +1,18 @@
|
||||
import { Component, SkipSelf } from '@angular/core';
|
||||
import { LeafService } from '../leaf.service';
|
||||
|
||||
// #docregion skipself-component
|
||||
@Component({
|
||||
selector: 'app-skipself',
|
||||
templateUrl: './skipself.component.html',
|
||||
styleUrls: ['./skipself.component.css'],
|
||||
// Angular would ignore this LeafService instance
|
||||
providers: [{ provide: LeafService, useValue: { emoji: '🍁' } }]
|
||||
})
|
||||
export class SkipselfComponent {
|
||||
// Use @SkipSelf() in the constructor
|
||||
constructor(@SkipSelf() public leaf: LeafService) { }
|
||||
}
|
||||
// #enddocregion skipself-component
|
||||
|
||||
// @SkipSelf(): Specifies that the dependency resolution should start from the parent injector, not here.
|
14
aio/content/examples/resolution-modifiers/src/index.html
Normal file
14
aio/content/examples/resolution-modifiers/src/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>DI Resolution Modifiers Example</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root>Loading...</app-root>
|
||||
</body>
|
||||
</html>
|
11
aio/content/examples/resolution-modifiers/src/main.ts
Normal file
11
aio/content/examples/resolution-modifiers/src/main.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
10
aio/content/examples/resolution-modifiers/stackblitz.json
Normal file
10
aio/content/examples/resolution-modifiers/stackblitz.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description": "NgModules",
|
||||
"files": [
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js",
|
||||
"!**/*.[1,2].*"
|
||||
],
|
||||
"file": "src/app/app.component.ts",
|
||||
"tags": ["NgModules"]
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"description": "Quickstart AppComponent Testing",
|
||||
"files":[
|
||||
"src/browser-test-shim.js",
|
||||
"src/app/app.component.ts",
|
||||
"src/app/app.component.spec.ts",
|
||||
"src/quickstart-specs.html"
|
||||
],
|
||||
"main": "src/quickstart-specs.html",
|
||||
"file": "src/app/app.component.spec.ts",
|
||||
"tags": ["quickstart", "setup", "testing"]
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
<!-- Run application specs in a browser -->
|
||||
<!-- #docregion -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<base href="/">
|
||||
<title>1st Specs</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<link rel="stylesheet" href="node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Polyfills -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
|
||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||
|
||||
<script src="node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
|
||||
<script src="node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
|
||||
<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>
|
||||
|
||||
<!-- #docregion files -->
|
||||
<script>
|
||||
var __spec_files__ = [
|
||||
'app/app.component.spec'
|
||||
];
|
||||
</script>
|
||||
<!-- #enddocregion files-->
|
||||
<script src="browser-test-shim.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"description": "QuickStart Setup",
|
||||
"files": [
|
||||
"src/app/app.component.ts",
|
||||
"src/app/app.module.ts",
|
||||
"src/index.html",
|
||||
"src/main.ts",
|
||||
"src/styles.css"
|
||||
],
|
||||
"file": "src/app/app.component.ts",
|
||||
"tags": ["quickstart", "setup", "seed"]
|
||||
}
|
@ -12,7 +12,7 @@ import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
|
||||
* then the templated elements are removed removed from the DOM,
|
||||
* the templated elements are (re)inserted into the DOM.
|
||||
*
|
||||
* <div *ngUnless="errorCount" class="success">
|
||||
* <div *appUnless="errorCount" class="success">
|
||||
* Congrats! Everything is great!
|
||||
* </div>
|
||||
*
|
||||
|
@ -1,24 +1,22 @@
|
||||
{
|
||||
"description": "Testing - specs",
|
||||
"files":[
|
||||
"src/expected.ts",
|
||||
"src/index-specs.html",
|
||||
"src/main-specs.ts",
|
||||
"src/styles.css",
|
||||
"src/test.css",
|
||||
"src/tests.sb.ts",
|
||||
|
||||
"e2e/src/**/*.ts",
|
||||
|
||||
"src/app/**/*.css",
|
||||
"src/app/**/*.html",
|
||||
"src/app/**/*.ts",
|
||||
"src/app/**/*.spec.ts",
|
||||
|
||||
"src/testing/*.ts",
|
||||
"src/testing/**/*",
|
||||
|
||||
"!src/main.ts",
|
||||
"!src/app/bag/*.*",
|
||||
"!src/app/1st.spec.ts",
|
||||
|
||||
"src/expected.ts",
|
||||
"src/test.css",
|
||||
"src/tests.sb.ts",
|
||||
"src/main-specs.ts",
|
||||
"src/index-specs.html"
|
||||
"src/**/*.spec.ts"
|
||||
],
|
||||
"main": "src/index-specs.html",
|
||||
"tags": ["testing"]
|
||||
|
@ -1,3 +1,3 @@
|
||||
const jasmineRequire = require('jasmine-core/lib/jasmine-core/jasmine.js');
|
||||
import jasmineRequire from 'jasmine-core/lib/jasmine-core/jasmine.js';
|
||||
|
||||
window['jasmineRequire'] = jasmineRequire;
|
||||
|
@ -1,19 +1,18 @@
|
||||
{
|
||||
"description": "Heroes Test App",
|
||||
"files":[
|
||||
"src/index.html",
|
||||
"src/main.ts",
|
||||
"src/styles.css",
|
||||
"src/test.css",
|
||||
|
||||
"e2e/src/**/*.ts",
|
||||
|
||||
"src/app/**/*.css",
|
||||
"src/app/**/*.html",
|
||||
"src/app/**/*.ts",
|
||||
|
||||
"!src/app/bag/*.*",
|
||||
|
||||
"!src/test.ts",
|
||||
|
||||
"src/test.css",
|
||||
"src/main.ts",
|
||||
"src/index.html"
|
||||
"!src/**/*.spec.ts"
|
||||
],
|
||||
"tags": ["testing"]
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ The following example shows how to make a simple progress bar accessible by usin
|
||||
|
||||
// Sets the minimum and maximum values for the progressbar role.
|
||||
'aria-valuemin': '0',
|
||||
'aria-valuemax': '0',
|
||||
'aria-valuemax': '100',
|
||||
|
||||
// Binding that updates the current value of the progressbar.
|
||||
'[attr.aria-valuenow]': 'value',
|
||||
@ -179,3 +179,8 @@ Books
|
||||
* "A Web for Everyone: Designing Accessible User Experiences", Sarah Horton and Whitney Quesenbery
|
||||
|
||||
* "Inclusive Design Patterns", Heydon Pickering
|
||||
|
||||
## More on accessibility
|
||||
|
||||
You may also be interested in the following:
|
||||
* [Audit your Angular app's accessibility with codelyzer](https://web.dev/accessible-angular-with-codelyzer/).
|
||||
|
@ -66,7 +66,7 @@ The following table lists some of the key AngularJS template features with their
|
||||
|
||||
### Bindings/interpolation
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="interpolation" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="interpolation"></code-example>
|
||||
|
||||
|
||||
In Angular, a template expression in curly braces still denotes one-way binding.
|
||||
@ -102,7 +102,7 @@ The following table lists some of the key AngularJS template features with their
|
||||
|
||||
### Pipes
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="uppercase" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="uppercase"></code-example>
|
||||
|
||||
|
||||
In Angular you use similar syntax with the pipe (|) character to filter output, but now you call them **pipes**.
|
||||
@ -136,7 +136,7 @@ The following table lists some of the key AngularJS template features with their
|
||||
|
||||
### Input variables
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="local" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="local"></code-example>
|
||||
|
||||
|
||||
Angular has true template input variables that are explicitly defined using the `let` keyword.
|
||||
@ -202,10 +202,10 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### Bootstrapping
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/main.ts" header="main.ts" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/main.ts" header="main.ts"></code-example>
|
||||
<br>
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" header="app.module.ts" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" header="app.module.ts"></code-example>
|
||||
|
||||
|
||||
Angular doesn't have a bootstrap directive.
|
||||
@ -245,7 +245,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### ngClass
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="ngClass" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="ngClass"></code-example>
|
||||
|
||||
|
||||
In Angular, the `ngClass` directive works similarly.
|
||||
@ -291,7 +291,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### Bind to the `click` event
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="event-binding" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="event-binding"></code-example>
|
||||
|
||||
|
||||
AngularJS event-based directives do not exist in Angular.
|
||||
@ -338,7 +338,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### Component decorator
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="component" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="component"></code-example>
|
||||
|
||||
|
||||
In Angular, the template no longer specifies its associated controller.
|
||||
@ -401,7 +401,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### Bind to the `href` property
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="href" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="href"></code-example>
|
||||
|
||||
|
||||
Angular uses property binding; there is no built-in *href* directive.
|
||||
@ -412,7 +412,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
In Angular, `href` is no longer used for routing. Routing uses `routerLink`, as shown in the following example.
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="router-link" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="router-link"></code-example>
|
||||
|
||||
|
||||
For more information on routing, see the [RouterLink binding](guide/router#router-link)
|
||||
@ -445,7 +445,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### *ngIf
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngIf" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngIf"></code-example>
|
||||
|
||||
|
||||
The `*ngIf` directive in Angular works the same as the `ng-if` directive in AngularJS. It removes
|
||||
@ -480,7 +480,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### ngModel
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngModel" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngModel"></code-example>
|
||||
|
||||
|
||||
In Angular, **two-way binding** is denoted by `[()]`, descriptively referred to as a "banana in a box". This syntax is a shortcut for defining both property binding (from the component to the view)
|
||||
@ -516,7 +516,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### *ngFor
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngFor" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngFor"></code-example>
|
||||
|
||||
|
||||
The `*ngFor` directive in Angular is similar to the `ng-repeat` directive in AngularJS. It repeats
|
||||
@ -559,7 +559,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### Bind to the `hidden` property
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="hidden" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="hidden"></code-example>
|
||||
|
||||
|
||||
Angular uses property binding; there is no built-in *show* directive.
|
||||
@ -598,7 +598,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### Bind to the `src` property
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="src" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="src"></code-example>
|
||||
|
||||
|
||||
Angular uses property binding; there is no built-in *src* directive.
|
||||
@ -635,7 +635,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### ngStyle
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="ngStyle" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="ngStyle"></code-example>
|
||||
|
||||
|
||||
In Angular, the `ngStyle` directive works similarly. It sets a CSS style on an HTML element based on an expression.
|
||||
@ -690,7 +690,7 @@ The following are some of the key AngularJS built-in directives and their equiva
|
||||
|
||||
### ngSwitch
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngSwitch" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.html" region="ngSwitch"></code-example>
|
||||
|
||||
|
||||
In Angular, the `ngSwitch` directive works similarly.
|
||||
@ -765,7 +765,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
### currency
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="currency" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="currency"></code-example>
|
||||
|
||||
|
||||
The Angular `currency` pipe is similar although some of the parameters have changed.
|
||||
@ -793,7 +793,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
### date
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="date" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="date"></code-example>
|
||||
|
||||
|
||||
The Angular `date` pipe is similar.
|
||||
@ -847,7 +847,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
### json
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="json" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="json"></code-example>
|
||||
|
||||
|
||||
The Angular `json` pipe does the same thing.
|
||||
@ -876,7 +876,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
### slice
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="slice" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="slice"></code-example>
|
||||
|
||||
|
||||
The `SlicePipe` does the same thing but the *order of the parameters is reversed*, in keeping
|
||||
@ -907,7 +907,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
### lowercase
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="lowercase" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="lowercase"></code-example>
|
||||
|
||||
|
||||
The Angular `lowercase` pipe does the same thing.
|
||||
@ -935,7 +935,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
||||
|
||||
### number
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="number" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.component.html" region="number"></code-example>
|
||||
|
||||
|
||||
The Angular `number` pipe is similar.
|
||||
@ -1068,7 +1068,7 @@ The Angular code is shown using TypeScript.
|
||||
|
||||
### NgModules
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts"></code-example>
|
||||
|
||||
|
||||
NgModules, defined with the `NgModule` decorator, serve the same purpose:
|
||||
@ -1109,7 +1109,7 @@ The Angular code is shown using TypeScript.
|
||||
|
||||
### Component decorator
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="component" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="component"></code-example>
|
||||
|
||||
|
||||
Angular adds a decorator to the component class to provide any required metadata.
|
||||
@ -1145,7 +1145,7 @@ The Angular code is shown using TypeScript.
|
||||
|
||||
### Component class
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="class" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="class"></code-example>
|
||||
|
||||
|
||||
In Angular, you create a component class.
|
||||
@ -1184,7 +1184,7 @@ The Angular code is shown using TypeScript.
|
||||
|
||||
### Dependency injection
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="di" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="di"></code-example>
|
||||
|
||||
|
||||
In Angular, you pass in dependencies as arguments to the component class constructor.
|
||||
@ -1254,7 +1254,7 @@ also encapsulate a style sheet within a specific component.
|
||||
|
||||
|
||||
### Styles configuration
|
||||
<code-example hideCopy path="ajs-quick-reference/.angular-cli.1.json" region="styles" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/.angular-cli.1.json" region="styles"></code-example>
|
||||
|
||||
With the Angular CLI, you can configure your global styles in the `angular.json` file.
|
||||
You can rename the extension to `.scss` to use sass.
|
||||
@ -1263,7 +1263,7 @@ also encapsulate a style sheet within a specific component.
|
||||
In Angular, you can use the `styles` or `styleUrls` property of the `@Component` metadata to define
|
||||
a style sheet for a particular component.
|
||||
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="style-url" linenums="false"></code-example>
|
||||
<code-example hideCopy path="ajs-quick-reference/src/app/movie-list.component.ts" region="style-url"></code-example>
|
||||
|
||||
|
||||
This allows you to set appropriate styles for individual components that won’t leak into
|
||||
|
179
aio/content/guide/angular-compiler-options.md
Normal file
179
aio/content/guide/angular-compiler-options.md
Normal file
@ -0,0 +1,179 @@
|
||||
# Angular compiler options
|
||||
|
||||
When you use [AoT compilation](guide/aot-compiler), you can control how your application is compiled by specifying *template* compiler options in the `tsconfig.json` [TypeScript configuration file](guide/typescript-configuration).
|
||||
|
||||
The template options object, `angularCompilerOptions`, is a sibling to the `compilerOptions` object that supplies standard options to the TypeScript compiler.
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
...
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"fullTemplateTypeCheck": true,
|
||||
"preserveWhitespaces": true,
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
{@a tsconfig-extends}
|
||||
## Configuration inheritance with extends
|
||||
|
||||
Like the TypeScript compiler, The Angular AoT compiler also supports `extends` in the `angularCompilerOptions` section of the TypeScript configuration file, `tsconfig.json`.
|
||||
The `extends` property is at the top level, parallel to `compilerOptions` and `angularCompilerOptions`.
|
||||
|
||||
A TypeScript configuration can inherit settings from another file using the `extends` property.
|
||||
The configuration options from the base file are loaded first, then overridden by those in the inheriting `tsconfig` file.
|
||||
|
||||
For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
...
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"fullTemplateTypeCheck": true,
|
||||
"preserveWhitespaces": true,
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For more informaton, see the [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html).
|
||||
|
||||
## Template options
|
||||
|
||||
The following options are available for configuring the AoT template compiler.
|
||||
|
||||
### `allowEmptyCodegenFiles`
|
||||
|
||||
When true, generate all possible files even if they are empty. Default is false. Used by the Bazel build rules to simplify how Bazel rules track file dependencies. Do not use this option outside of the Bazel rules.
|
||||
|
||||
### `annotationsAs`
|
||||
|
||||
Modifies how Angular-specific annotations are emitted to improve tree-shaking. Non-Angular annotations are not affected. One of `static fields` (the default) or `decorators`.
|
||||
|
||||
* By default, the compiler replaces decorators with a static field in the class, which allows advanced tree-shakers like [Closure compiler](https://github.com/google/closure-compiler) to remove unused classes.
|
||||
|
||||
* The `decorators` value leaves the decorators in place, which makes compilation faster. TypeScript emits calls to the` __decorate` helper. Use `--emitDecoratorMetadata` for runtime reflection (but note that the resulting code will not properly tree-shake.
|
||||
|
||||
### `annotateForClosureCompiler`
|
||||
|
||||
When true, use [Tsickle](https://github.com/angular/tsickle) to annotate the emitted JavaScript with [JSDoc](http://usejsdoc.org/) comments needed by the
|
||||
[Closure Compiler](https://github.com/google/closure-compiler). Default is false.
|
||||
|
||||
### `disableExpressionLowering`
|
||||
|
||||
When true (the default), transforms code that is or could be used in an annotation, to allow it to be imported from template factory modules. See [metadata rewriting](guide/aot-compiler#metadata-rewriting) for more information.
|
||||
|
||||
When `false`, disables this rewriting, requiring the rewriting to be done manually.
|
||||
|
||||
### `disableTypeScriptVersionCheck`
|
||||
|
||||
When `true`, the compiler does not check the TypeScript version and does not report an error when an unsupported version of TypeScript is used. Not recommended, as unsupported versions of TypeScript might have undefined behavior. Default is false.
|
||||
|
||||
### `enableResourceInlining`
|
||||
|
||||
When true, replaces the `templateUrl` and `styleUrls` property in all `@Component` decorators with inlined contents in `template` and `styles` properties.
|
||||
|
||||
When enabled, the `.js` output of `ngc` does not include any lazy-loaded template or style URLs.
|
||||
|
||||
|
||||
{@a enablelegacytemplate}
|
||||
|
||||
### `enableLegacyTemplate`
|
||||
|
||||
When true, enables use of the `<template>` element, which was deprecated in Angular 4.0, in favor of `<ng-template>` (to avoid colliding with the DOM's element of the same name). Default is false. Might be required by some third-party Angular libraries.
|
||||
|
||||
### `flatModuleId`
|
||||
|
||||
The module ID to use for importing a flat module (when `flatModuleOutFile` is true). References generated by the template compiler use this module name when importing symbols
|
||||
from the flat module. Ignored if `flatModuleOutFile` is false.
|
||||
|
||||
### `flatModuleOutFile`
|
||||
|
||||
When true, generates a flat module index of the given file name and the corresponding flat module metadata. Use to create flat modules that are packaged similarly to `@angular/core` and `@angular/common`. When this option is used, the `package.json` for the library should refer
|
||||
to the generated flat module index instead of the library index file.
|
||||
|
||||
Produces only one `.metadata.json` file, which contains all the metadata necessary
|
||||
for symbols exported from the library index. In the generated `.ngfactory.js` files, the flat
|
||||
module index is used to import symbols that includes both the public API from the library index
|
||||
as well as shrowded internal symbols.
|
||||
|
||||
By default the `.ts` file supplied in the `files` field is assumed to be the library index.
|
||||
If more than one `.ts` file is specified, `libraryIndex` is used to select the file to use.
|
||||
If more than one `.ts` file is supplied without a `libraryIndex`, an error is produced.
|
||||
|
||||
A flat module index `.d.ts` and `.js` is created with the given `flatModuleOutFile` name in the same location as the library index `.d.ts` file.
|
||||
|
||||
For example, if a library uses the `public_api.ts` file as the library index of the module, the `tsconfig.json` `files` field would be `["public_api.ts"]`.
|
||||
The `flatModuleOutFile` options could then be set to (for example) `"index.js"`, which produces `index.d.ts` and `index.metadata.json` files.
|
||||
The `module` field of the library's `package.json` would be `"index.js"` and the `typings` field
|
||||
would be `"index.d.ts"`.
|
||||
|
||||
### `fullTemplateTypeCheck`
|
||||
|
||||
When true (recommended), enables the [binding expression validation](guide/aot-compiler#binding-expression-validation) phase of the template compiler, which uses TypeScript to validate binding expressions.
|
||||
|
||||
Default is currently false.
|
||||
|
||||
### `generateCodeForLibraries`
|
||||
|
||||
When true (the default), generates factory files (`.ngfactory.js` and `.ngstyle.js`)
|
||||
for `.d.ts` files with a corresponding `.metadata.json` file.
|
||||
|
||||
When false, factory files are generated only for `.ts` files. Do this when using factory summaries.
|
||||
|
||||
|
||||
### `preserveWhitespaces`
|
||||
|
||||
When false (the default), removes blank text nodes from compiled templates, which results in smaller emitted template factory modules. Set to true to preserve blank text nodes.
|
||||
|
||||
### `skipMetadataEmit`
|
||||
|
||||
When true, does not to produce `.metadata.json` files. Default is `false`.
|
||||
|
||||
The `.metadata.json` files contain information 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 includes, 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.
|
||||
|
||||
You can set to `true` when using factory summaries, because the factory summaries
|
||||
include a copy of the information that is in the `.metadata.json` file.
|
||||
|
||||
Set to `true` if you are using TypeScript's `--outFile` option, because the metadata files
|
||||
are not valid for this style of TypeScript output. However, we do not recommend using `--outFile` with Angular. Use a bundler, such as [webpack](https://webpack.js.org/), instead.
|
||||
|
||||
### `skipTemplateCodegen`
|
||||
|
||||
When true, does not emit `.ngfactory.js` and `.ngstyle.js` files. This turns off most of the template compiler and disables the reporting of template diagnostics.
|
||||
|
||||
Can be used to instruct the template compiler to produce `.metadata.json` files for distribution with an `npm` package while avoiding the production of `.ngfactory.js` and `.ngstyle.js` files that cannot be distributed to `npm`.
|
||||
|
||||
### `strictMetadataEmit`
|
||||
|
||||
When true, reports an error to the `.metadata.json` file if `"skipMetadataEmit"` is `false`.
|
||||
Default is false. Use only when `"skipMetadataEmit"` is false and `"skipTemplateCodeGen"` is true.
|
||||
|
||||
This option is intended to validate the `.metadata.json` files emitted for bundling with an `npm` package. The validation is strict and can emit errors for metadata that would never produce an error when used by the template compiler. You can choose to suppress the error emitted by this option for an exported symbol by including `@dynamic` in the comment documenting the symbol.
|
||||
|
||||
It is valid for `.metadata.json` files to contain errors.
|
||||
The template compiler reports these errors if the metadata is used to determine the contents of an annotation.
|
||||
The metadata collector cannot predict the symbols that are designed for use in an annotation, so it preemptively includes error nodes in the metadata for the exported symbols.
|
||||
The template compiler can then use the error nodes to report an error if these symbols are used.
|
||||
|
||||
If the client of a library intends to use a symbol in an annotation, the template compiler does not normally report this until the client uses the symbol.
|
||||
This option allows detection of these errors during the build phase of
|
||||
the library and is used, for example, in producing Angular libraries themselves.
|
||||
|
||||
### `strictInjectionParameters`
|
||||
|
||||
When true (recommended), reports an error for a supplied parameter whose injection type cannot be determined. When false (currently the default), constructor parameters of classes marked with `@Injectable` whose type cannot be resolved produce a warning.
|
||||
|
||||
### `trace`
|
||||
|
||||
When true, prints extra information while compiling templates. Default is false.
|
@ -37,8 +37,7 @@ To get started with adding Angular animations to your project, import the animat
|
||||
|
||||
Import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
|
||||
|
||||
<code-example path="animations/src/app/app.module.1.ts" header="src/app/app.module.ts" language="typescript" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="animations/src/app/app.module.1.ts" header="src/app/app.module.ts" language="typescript"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@ -129,7 +128,7 @@ The third argument, `easing`, controls how the animation [accelerates and decele
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note:** See the Angular Material Design website's topic on [Natural easing curves](https://material.io/design/motion/speed.html#easing) for general information on easing curves.
|
||||
**Note:** See the Material Design website's topic on [Natural easing curves](https://material.io/design/motion/speed.html#easing) for general information on easing curves.
|
||||
</div>
|
||||
|
||||
This example provides a state transition from `open` to `closed` with a one second transition between states.
|
||||
@ -180,9 +179,7 @@ In this example, we'll name the trigger `openClose`, and attach it to the `butto
|
||||
|
||||
Animations are defined in the metadata of the component that controls the HTML element to be animated. Put the code that defines your animations under the `animations:` property within the `@Component()` decorator.
|
||||
|
||||
<code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript"
|
||||
region="component" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript" region="component"></code-example>
|
||||
|
||||
When you've defined an animation trigger for a component, you can attach it to an element in that component's template by wrapping the trigger name in brackets and preceding it with an `@` symbol. Then, you can bind the trigger to a template expression using standard Angular property binding syntax as shown below, where `triggerName` is the name of the trigger, and `expression` evaluates to a defined animation state.
|
||||
|
||||
@ -263,7 +260,7 @@ What it does
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>state()</code></td>
|
||||
<td><code><a href="api/animations/state" class="code-anchor">state()</a></code></td>
|
||||
<td>Creates a named set of CSS styles that should be applied on successful transition to a given state. The state can then be referenced by name within other animation functions.</td>
|
||||
</tr>
|
||||
|
||||
@ -283,7 +280,7 @@ What it does
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>group()</code></td>
|
||||
<td><code><a href="api/animations/group" class="code-anchor">group()</a></code></td>
|
||||
<td>Specifies a group of animation steps (<em>inner animations</em>) to be run in parallel. Animation continues only after all inner animation steps have completed. Used within <code>sequence()</code> or <code>transition().</code></td>
|
||||
</tr>
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
540
aio/content/guide/aot-metadata-errors.md
Normal file
540
aio/content/guide/aot-metadata-errors.md
Normal file
@ -0,0 +1,540 @@
|
||||
# AoT metadata errors
|
||||
|
||||
The following are metadata errors you may encounter, with explanations and suggested corrections.
|
||||
|
||||
[Expression form not supported](#expression-form-not-supported)<br>
|
||||
[Reference to a local (non-exported) symbol](#reference-to-a-local-symbol)<br>
|
||||
[Only initialized variables and constants](#only-initialized-variables)<br>
|
||||
[Reference to a non-exported class](#reference-to-a-non-exported-class)<br>
|
||||
[Reference to a non-exported function](#reference-to-a-non-exported-function)<br>
|
||||
[Function calls are not supported](#function-calls-not-supported)<br>
|
||||
[Destructured variable or constant not supported](#destructured-variable-not-supported)<br>
|
||||
[Could not resolve type](#could-not-resolve-type)<br>
|
||||
[Name expected](#name-expected)<br>
|
||||
[Unsupported enum member name](#unsupported-enum-member-name)<br>
|
||||
[Tagged template expressions are not supported](#tagged-template-expressions-not-supported)<br>
|
||||
[Symbol reference expected](#symbol-reference-expected)<br>
|
||||
|
||||
<hr>
|
||||
|
||||
{@a expression-form-not-supported}
|
||||
## Expression form not supported
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
*The compiler encountered an expression it didn't understand while evaluating Angular metadata.*
|
||||
|
||||
</div>
|
||||
|
||||
Language features outside of the compiler's [restricted expression syntax](guide/aot-compiler#expression-syntax)
|
||||
can produce this error, as seen in the following example:
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
export class Fooish { ... }
|
||||
...
|
||||
const prop = typeof Fooish; // typeof is not valid in metadata
|
||||
...
|
||||
// bracket notation is not valid in metadata
|
||||
{ provide: 'token', useValue: { [prop]: 'value' } };
|
||||
...
|
||||
```
|
||||
|
||||
You can use `typeof` and bracket notation in normal application code.
|
||||
You just can't use those features within expressions that define Angular metadata.
|
||||
|
||||
Avoid this error by sticking to the compiler's [restricted expression syntax](guide/aot-compiler#expression-syntax)
|
||||
when writing Angular metadata
|
||||
and be wary of new or unusual TypeScript features.
|
||||
|
||||
<hr>
|
||||
|
||||
{@a reference-to-a-local-symbol}
|
||||
## Reference to a local (non-exported) symbol
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
_Reference to a local (non-exported) symbol 'symbol name'. Consider exporting the symbol._
|
||||
|
||||
</div>
|
||||
|
||||
The compiler encountered a referenced to a locally defined symbol that either wasn't exported or wasn't initialized.
|
||||
|
||||
Here's a `provider` example of the problem.
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
let foo: number; // neither exported nor initialized
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: ... ,
|
||||
providers: [
|
||||
{ provide: Foo, useValue: foo }
|
||||
]
|
||||
})
|
||||
export class MyComponent {}
|
||||
```
|
||||
The compiler generates the component factory, which includes the `useValue` provider code, in a separate module. _That_ factory module can't reach back to _this_ source module to access the local (non-exported) `foo` variable.
|
||||
|
||||
You could fix the problem by initializing `foo`.
|
||||
|
||||
```ts
|
||||
let foo = 42; // initialized
|
||||
```
|
||||
|
||||
The compiler will [fold](guide/aot-compiler#code-folding) the expression into the provider as if you had written this.
|
||||
|
||||
```ts
|
||||
providers: [
|
||||
{ provide: Foo, useValue: 42 }
|
||||
]
|
||||
```
|
||||
|
||||
Alternatively, you can fix it by exporting `foo` with the expectation that `foo` will be assigned at runtime when you actually know its value.
|
||||
|
||||
```ts
|
||||
// CORRECTED
|
||||
export let foo: number; // exported
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: ... ,
|
||||
providers: [
|
||||
{ provide: Foo, useValue: foo }
|
||||
]
|
||||
})
|
||||
export class MyComponent {}
|
||||
```
|
||||
|
||||
Adding `export` often works for variables referenced in metadata such as `providers` and `animations` because the compiler can generate _references_ to the exported variables in these expressions. It doesn't need the _values_ of those variables.
|
||||
|
||||
Adding `export` doesn't work when the compiler needs the _actual value_
|
||||
in order to generate code.
|
||||
For example, it doesn't work for the `template` property.
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
export let someTemplate: string; // exported but not initialized
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: someTemplate
|
||||
})
|
||||
export class MyComponent {}
|
||||
```
|
||||
|
||||
The compiler needs the value of the `template` property _right now_ to generate the component factory.
|
||||
The variable reference alone is insufficient.
|
||||
Prefixing the declaration with `export` merely produces a new error, "[`Only initialized variables and constants can be referenced`](#only-initialized-variables)".
|
||||
|
||||
<hr>
|
||||
|
||||
{@a only-initialized-variables}
|
||||
## Only initialized variables and constants
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
_Only initialized variables and constants can be referenced because the value of this variable is needed by the template compiler._
|
||||
|
||||
</div>
|
||||
|
||||
The compiler found a reference to an exported variable or static field that wasn't initialized.
|
||||
It needs the value of that variable to generate code.
|
||||
|
||||
The following example tries to set the component's `template` property to the value of
|
||||
the exported `someTemplate` variable which is declared but _unassigned_.
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
export let someTemplate: string;
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: someTemplate
|
||||
})
|
||||
export class MyComponent {}
|
||||
```
|
||||
|
||||
You'd also get this error if you imported `someTemplate` from some other module and neglected to initialize it there.
|
||||
|
||||
```ts
|
||||
// ERROR - not initialized there either
|
||||
import { someTemplate } from './config';
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: someTemplate
|
||||
})
|
||||
export class MyComponent {}
|
||||
```
|
||||
|
||||
The compiler cannot wait until runtime to get the template information.
|
||||
It must statically derive the value of the `someTemplate` variable from the source code
|
||||
so that it can generate the component factory, which includes
|
||||
instructions for building the element based on the template.
|
||||
|
||||
To correct this error, provide the initial value of the variable in an initializer clause _on the same line_.
|
||||
|
||||
```ts
|
||||
// CORRECTED
|
||||
export let someTemplate = '<h1>Greetings from Angular</h1>';
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: someTemplate
|
||||
})
|
||||
export class MyComponent {}
|
||||
```
|
||||
|
||||
<hr>
|
||||
|
||||
{@a reference-to-a-non-exported-class}
|
||||
## Reference to a non-exported class
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
_Reference to a non-exported class <class name>. Consider exporting the class._
|
||||
|
||||
</div>
|
||||
|
||||
Metadata referenced a class that wasn't exported.
|
||||
|
||||
For example, you may have defined a class and used it as an injection token in a providers array
|
||||
but neglected to export that class.
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
abstract class MyStrategy { }
|
||||
|
||||
...
|
||||
providers: [
|
||||
{ provide: MyStrategy, useValue: ... }
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
Angular generates a class factory in a separate module and that
|
||||
factory [can only access exported classes](guide/aot-compiler#exported-symbols).
|
||||
To correct this error, export the referenced class.
|
||||
|
||||
```ts
|
||||
// CORRECTED
|
||||
export abstract class MyStrategy { }
|
||||
|
||||
...
|
||||
providers: [
|
||||
{ provide: MyStrategy, useValue: ... }
|
||||
]
|
||||
...
|
||||
```
|
||||
<hr>
|
||||
|
||||
{@a reference-to-a-non-exported-function}
|
||||
## Reference to a non-exported function
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
*Metadata referenced a function that wasn't exported.*
|
||||
|
||||
</div>
|
||||
|
||||
For example, you may have set a providers `useFactory` property to a locally defined function that you neglected to export.
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
function myStrategy() { ... }
|
||||
|
||||
...
|
||||
providers: [
|
||||
{ provide: MyStrategy, useFactory: myStrategy }
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
Angular generates a class factory in a separate module and that
|
||||
factory [can only access exported functions](guide/aot-compiler#exported-symbols).
|
||||
To correct this error, export the function.
|
||||
|
||||
```ts
|
||||
// CORRECTED
|
||||
export function myStrategy() { ... }
|
||||
|
||||
...
|
||||
providers: [
|
||||
{ provide: MyStrategy, useFactory: myStrategy }
|
||||
]
|
||||
...
|
||||
```
|
||||
<hr>
|
||||
|
||||
{@a function-calls-not-supported}
|
||||
## Function calls are not supported
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
_Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function._
|
||||
|
||||
</div>
|
||||
|
||||
The compiler does not currently support [function expressions or lambda functions](guide/aot-compiler#function-expression).
|
||||
For example, you cannot set a provider's `useFactory` to an anonymous function or arrow function like this.
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
...
|
||||
providers: [
|
||||
{ provide: MyStrategy, useFactory: function() { ... } },
|
||||
{ provide: OtherStrategy, useFactory: () => { ... } }
|
||||
]
|
||||
...
|
||||
```
|
||||
You also get this error if you call a function or method in a provider's `useValue`.
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
import { calculateValue } from './utilities';
|
||||
|
||||
...
|
||||
providers: [
|
||||
{ provide: SomeValue, useValue: calculateValue() }
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
To correct this error, export a function from the module and refer to the function in a `useFactory` provider instead.
|
||||
|
||||
```ts
|
||||
// CORRECTED
|
||||
import { calculateValue } from './utilities';
|
||||
|
||||
export function myStrategy() { ... }
|
||||
export function otherStrategy() { ... }
|
||||
export function someValueFactory() {
|
||||
return calculateValue();
|
||||
}
|
||||
...
|
||||
providers: [
|
||||
{ provide: MyStrategy, useFactory: myStrategy },
|
||||
{ provide: OtherStrategy, useFactory: otherStrategy },
|
||||
{ provide: SomeValue, useFactory: someValueFactory }
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
<hr>
|
||||
|
||||
{@a destructured-variable-not-supported}
|
||||
## Destructured variable or constant not supported
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
_Referencing an exported destructured variable or constant is not supported by the template compiler. Consider simplifying this to avoid destructuring._
|
||||
|
||||
</div>
|
||||
|
||||
The compiler does not support references to variables assigned by [destructuring](https://www.typescriptlang.org/docs/handbook/variable-declarations.html#destructuring).
|
||||
|
||||
For example, you cannot write something like this:
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
import { configuration } from './configuration';
|
||||
|
||||
// destructured assignment to foo and bar
|
||||
const {foo, bar} = configuration;
|
||||
...
|
||||
providers: [
|
||||
{provide: Foo, useValue: foo},
|
||||
{provide: Bar, useValue: bar},
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
To correct this error, refer to non-destructured values.
|
||||
|
||||
```ts
|
||||
// CORRECTED
|
||||
import { configuration } from './configuration';
|
||||
...
|
||||
providers: [
|
||||
{provide: Foo, useValue: configuration.foo},
|
||||
{provide: Bar, useValue: configuration.bar},
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
<hr>
|
||||
|
||||
{@a could-not-resolve-type}
|
||||
## Could not resolve type
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
*The compiler encountered a type and can't determine which module exports that type.*
|
||||
|
||||
</div>
|
||||
|
||||
This can happen if you refer to an ambient type.
|
||||
For example, the `Window` type is an ambient type declared in the global `.d.ts` file.
|
||||
|
||||
You'll get an error if you reference it in the component constructor,
|
||||
which the compiler must statically analyze.
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
@Component({ })
|
||||
export class MyComponent {
|
||||
constructor (private win: Window) { ... }
|
||||
}
|
||||
```
|
||||
TypeScript understands ambient types so you don't import them.
|
||||
The Angular compiler does not understand a type that you neglect to export or import.
|
||||
|
||||
In this case, the compiler doesn't understand how to inject something with the `Window` token.
|
||||
|
||||
Do not refer to ambient types in metadata expressions.
|
||||
|
||||
If you must inject an instance of an ambient type,
|
||||
you can finesse the problem in four steps:
|
||||
|
||||
1. Create an injection token for an instance of the ambient type.
|
||||
1. Create a factory function that returns that instance.
|
||||
1. Add a `useFactory` provider with that factory function.
|
||||
1. Use `@Inject` to inject the instance.
|
||||
|
||||
Here's an illustrative example.
|
||||
|
||||
```ts
|
||||
// CORRECTED
|
||||
import { Inject } from '@angular/core';
|
||||
|
||||
export const WINDOW = new InjectionToken('Window');
|
||||
export function _window() { return window; }
|
||||
|
||||
@Component({
|
||||
...
|
||||
providers: [
|
||||
{ provide: WINDOW, useFactory: _window }
|
||||
]
|
||||
})
|
||||
export class MyComponent {
|
||||
constructor (@Inject(WINDOW) private win: Window) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
The `Window` type in the constructor is no longer a problem for the compiler because it
|
||||
uses the `@Inject(WINDOW)` to generate the injection code.
|
||||
|
||||
Angular does something similar with the `DOCUMENT` token so you can inject the browser's `document` object (or an abstraction of it, depending upon the platform in which the application runs).
|
||||
|
||||
```ts
|
||||
import { Inject } from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/platform-browser';
|
||||
|
||||
@Component({ ... })
|
||||
export class MyComponent {
|
||||
constructor (@Inject(DOCUMENT) private doc: Document) { ... }
|
||||
}
|
||||
```
|
||||
<hr>
|
||||
|
||||
{@a name-expected}
|
||||
## Name expected
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
*The compiler expected a name in an expression it was evaluating.*
|
||||
|
||||
</div>
|
||||
|
||||
This can happen if you use a number as a property name as in the following example.
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
provider: [{ provide: Foo, useValue: { 0: 'test' } }]
|
||||
```
|
||||
|
||||
Change the name of the property to something non-numeric.
|
||||
|
||||
```ts
|
||||
// CORRECTED
|
||||
provider: [{ provide: Foo, useValue: { '0': 'test' } }]
|
||||
```
|
||||
|
||||
<hr>
|
||||
|
||||
{@a unsupported-enum-member-name}
|
||||
## Unsupported enum member name
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
*Angular couldn't determine the value of the [enum member](https://www.typescriptlang.org/docs/handbook/enums.html) that you referenced in metadata.*
|
||||
|
||||
</div>
|
||||
|
||||
The compiler can understand simple enum values but not complex values such as those derived from computed properties.
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
enum Colors {
|
||||
Red = 1,
|
||||
White,
|
||||
Blue = "Blue".length // computed
|
||||
}
|
||||
|
||||
...
|
||||
providers: [
|
||||
{ provide: BaseColor, useValue: Colors.White } // ok
|
||||
{ provide: DangerColor, useValue: Colors.Red } // ok
|
||||
{ provide: StrongColor, useValue: Colors.Blue } // bad
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
Avoid referring to enums with complicated initializers or computed properties.
|
||||
|
||||
<hr>
|
||||
|
||||
{@a tagged-template-expressions-not-supported}
|
||||
## Tagged template expressions are not supported
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
_Tagged template expressions are not supported in metadata._
|
||||
|
||||
</div>
|
||||
|
||||
The compiler encountered a JavaScript ES2015 [tagged template expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals) such as the following.
|
||||
|
||||
```ts
|
||||
// ERROR
|
||||
const expression = 'funky';
|
||||
const raw = String.raw`A tagged template ${expression} string`;
|
||||
...
|
||||
template: '<div>' + raw + '</div>'
|
||||
...
|
||||
```
|
||||
[`String.raw()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw)
|
||||
is a _tag function_ native to JavaScript ES2015.
|
||||
|
||||
The AoT compiler does not support tagged template expressions; avoid them in metadata expressions.
|
||||
|
||||
<hr>
|
||||
|
||||
{@a symbol-reference-expected}
|
||||
## Symbol reference expected
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
*The compiler expected a reference to a symbol at the location specified in the error message.*
|
||||
|
||||
</div>
|
||||
|
||||
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).
|
||||
|
||||
-->
|
@ -10,7 +10,7 @@ Learn more in [The App Shell Model](https://developers.google.com/web/fundamenta
|
||||
## Step 1: Prepare the application
|
||||
|
||||
You can do this with the following CLI command:
|
||||
<code-example format="." language="bash" linenums="false">
|
||||
<code-example language="bash">
|
||||
ng new my-app --routing
|
||||
</code-example>
|
||||
|
||||
@ -20,7 +20,7 @@ For an existing application, you have to manually add the `RouterModule` and def
|
||||
|
||||
Use the CLI to automatically create the app shell.
|
||||
|
||||
<code-example format="." language="bash" linenums="false">
|
||||
<code-example language="bash">
|
||||
ng generate app-shell --client-project my-app --universal-project server-app
|
||||
</code-example>
|
||||
|
||||
@ -29,7 +29,7 @@ ng generate app-shell --client-project my-app --universal-project server-app
|
||||
|
||||
After running this command you will notice that the `angular.json` configuration file has been updated to add two new targets, with a few other changes.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example language="json">
|
||||
"server": {
|
||||
"builder": "@angular-devkit/build-angular:server",
|
||||
"options": {
|
||||
@ -44,6 +44,12 @@ After running this command you will notice that the `angular.json` configuration
|
||||
"browserTarget": "my-app:build",
|
||||
"serverTarget": "my-app:server",
|
||||
"route": "shell"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "my-app:build:production",
|
||||
"serverTarget": "my-app:server:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
</code-example>
|
||||
@ -52,8 +58,16 @@ After running this command you will notice that the `angular.json` configuration
|
||||
|
||||
Use the CLI to build the `app-shell` target.
|
||||
|
||||
<code-example format="." language="bash" linenums="false">
|
||||
<code-example language="bash">
|
||||
ng run my-app:app-shell
|
||||
</code-example>
|
||||
|
||||
Or to use the production configuration.
|
||||
|
||||
<code-example language="bash">
|
||||
ng run my-app:app-shell:production
|
||||
</code-example>
|
||||
|
||||
To verify the build output, open `dist/my-app/index.html`. Look for default text `app-shell works!` to show that the app shell route was rendered as part of the output.
|
||||
|
||||
|
||||
|
@ -10,12 +10,12 @@ For example, individual components define and control each of the following view
|
||||
You define a component's application logic—what it does to support the view—inside a class.
|
||||
The class interacts with the view through an API of properties and methods.
|
||||
|
||||
For example, `HeroListComponent` has a `heroes` property that holds an array of heroes.
|
||||
Its `selectHero()` method sets a `selectedHero` property when the user clicks to choose a hero from that list.
|
||||
The component acquires the heroes from a service, which is a TypeScript [parameter property](http://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties) on the constructor.
|
||||
For example, `HeroListComponent` has a `heroes` property that holds an array of heroes.
|
||||
Its `selectHero()` method sets a `selectedHero` property when the user clicks to choose a hero from that list.
|
||||
The component acquires the heroes from a service, which is a TypeScript [parameter property](http://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties) on the constructor.
|
||||
The service is provided to the component through the dependency injection system.
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (class)" region="class"></code-example>
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" header="src/app/hero-list.component.ts (class)" region="class"></code-example>
|
||||
|
||||
Angular creates, updates, and destroys components as the user moves through the application. Your app can take action at each moment in this lifecycle through optional [lifecycle hooks](guide/lifecycle-hooks), like `ngOnInit()`.
|
||||
|
||||
@ -31,7 +31,7 @@ In addition to containing or pointing to the template, the `@Component` metadata
|
||||
|
||||
Here's an example of basic metadata for `HeroListComponent`.
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" header="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
|
||||
|
||||
This example shows some of the most useful `@Component` configuration options:
|
||||
|
||||
@ -40,7 +40,7 @@ Angular inserts an instance of the `HeroListComponent` view between those tags.
|
||||
|
||||
* `templateUrl`: The module-relative address of this component's HTML template. Alternatively, you can provide the HTML template inline, as the value of the `template` property. This template defines the component's *host view*.
|
||||
|
||||
* `providers`: An array of [providers](guide/glossary#provider) for services that the component requires. In the example, this tells Angular how to provide the `HeroService` instance that the component's constructor uses to get the list of heroes to display.
|
||||
* `providers`: An array of [providers](guide/glossary#provider) for services that the component requires. In the example, this tells Angular how to provide the `HeroService` instance that the component's constructor uses to get the list of heroes to display.
|
||||
|
||||
|
||||
## Templates and views
|
||||
@ -69,7 +69,7 @@ This template uses typical HTML elements like `<h2>` and `<p>`, and also includ
|
||||
|
||||
* The `*ngFor` directive tells Angular to iterate over a list.
|
||||
* `{{hero.name}}`, `(click)`, and `[hero]` bind program data to and from the DOM, responding to user input. See more about [data binding](#data-binding) below.
|
||||
* The `<app-hero-detail>` tag in the example is an element that represents a new component, `HeroDetailComponent`.
|
||||
* The `<app-hero-detail>` tag in the example is an element that represents a new component, `HeroDetailComponent`.
|
||||
`HeroDetailComponent` (code not shown) defines the hero-detail child view of `HeroListComponent`.
|
||||
Notice how custom components like this mix seamlessly with native HTML in the same layouts.
|
||||
|
||||
@ -87,7 +87,7 @@ The following diagram shows the four forms of data binding markup. Each form has
|
||||
|
||||
This example from the `HeroListComponent` template uses three of these forms.
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" header="src/app/hero-list.component.html (binding)" region="binding"></code-example>
|
||||
<code-example path="architecture/src/app/hero-list.component.1.html" header="src/app/hero-list.component.html (binding)" region="binding"></code-example>
|
||||
|
||||
* The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation)
|
||||
displays the component's `hero.name` property value within the `<li>` element.
|
||||
@ -97,11 +97,11 @@ displays the component's `hero.name` property value within the `<li>` element.
|
||||
|
||||
* The `(click)` [*event binding*](guide/user-input#binding-to-user-input-events) calls the component's `selectHero` method when the user clicks a hero's name.
|
||||
|
||||
Two-way data binding (used mainly in [template-driven forms](guide/forms))
|
||||
combines property and event binding in a single notation.
|
||||
Two-way data binding (used mainly in [template-driven forms](guide/forms))
|
||||
combines property and event binding in a single notation.
|
||||
Here's an example from the `HeroDetailComponent` template that uses two-way data binding with the `ngModel` directive.
|
||||
|
||||
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
||||
<code-example path="architecture/src/app/hero-detail.component.html" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
||||
|
||||
In two-way binding, a data property value flows to the input box from the component as with property binding.
|
||||
The user's changes also flow back to the component, resetting the property to the latest value,
|
||||
@ -151,20 +151,20 @@ Angular templates are *dynamic*. When Angular renders them, it transforms the DO
|
||||
|
||||
A component is technically a directive.
|
||||
However, components are so distinctive and central to Angular applications that Angular
|
||||
defines the `@Component()` decorator, which extends the `@Directive()` decorator with
|
||||
defines the `@Component()` decorator, which extends the `@Directive()` decorator with
|
||||
template-oriented features.
|
||||
|
||||
In addition to components, there are two other kinds of directives: *structural* and *attribute*.
|
||||
In addition to components, there are two other kinds of directives: *structural* and *attribute*.
|
||||
Angular defines a number of directives of both kinds, and you can define your own using the `@Directive()` decorator.
|
||||
|
||||
Just as for components, the metadata for a directive associates the decorated class with a `selector` element that you use to insert it into HTML. In templates, directives typically appear within an element tag as attributes, either by name or as the target of an assignment or a binding.
|
||||
|
||||
#### Structural directives
|
||||
|
||||
*Structural directives* alter layout by adding, removing, and replacing elements in the DOM.
|
||||
*Structural directives* alter layout by adding, removing, and replacing elements in the DOM.
|
||||
The example template uses two built-in structural directives to add application logic to how the view is rendered.
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" header="src/app/hero-list.component.html (structural)" region="structural"></code-example>
|
||||
<code-example path="architecture/src/app/hero-list.component.1.html" header="src/app/hero-list.component.html (structural)" region="structural"></code-example>
|
||||
|
||||
* [`*ngFor`](guide/displaying-data#ngFor) is an iterative; it tells Angular to stamp out one `<li>` per hero in the `heroes` list.
|
||||
* [`*ngIf`](guide/displaying-data#ngIf) is a conditional; it includes the `HeroDetail` component only if a selected hero exists.
|
||||
@ -176,7 +176,7 @@ In templates they look like regular HTML attributes, hence the name.
|
||||
|
||||
The `ngModel` directive, which implements two-way data binding, is an example of an attribute directive. `ngModel` modifies the behavior of an existing element (typically `<input>`) by setting its display value property and responding to change events.
|
||||
|
||||
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
||||
<code-example path="architecture/src/app/hero-detail.component.html" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
|
||||
|
||||
Angular has more pre-defined directives that either alter the layout structure
|
||||
(for example, [ngSwitch](guide/template-syntax#ngSwitch))
|
||||
|
@ -23,7 +23,7 @@ An NgModule is defined by a class decorated with `@NgModule()`. The `@NgModule()
|
||||
|
||||
Here's a simple root NgModule definition.
|
||||
|
||||
<code-example path="architecture/src/app/mini-app.ts" region="module" header="src/app/app.module.ts" linenums="false"></code-example>
|
||||
<code-example path="architecture/src/app/mini-app.ts" region="module" header="src/app/app.module.ts"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@ -69,9 +69,9 @@ In JavaScript each *file* is a module and all objects defined in the file belong
|
||||
The module declares some objects to be public by marking them with the `export` key word.
|
||||
Other JavaScript modules use *import statements* to access public objects from other modules.
|
||||
|
||||
<code-example path="architecture/src/app/app.module.ts" region="imports" linenums="false"></code-example>
|
||||
<code-example path="architecture/src/app/app.module.ts" region="imports"></code-example>
|
||||
|
||||
<code-example path="architecture/src/app/app.module.ts" region="export" linenums="false"></code-example>
|
||||
<code-example path="architecture/src/app/app.module.ts" region="export"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
<a href="http://exploringjs.com/es6/ch_modules.html">Learn more about the JavaScript module system on the web.</a>
|
||||
@ -87,17 +87,17 @@ Angular loads as a collection of JavaScript modules. You can think of them as li
|
||||
|
||||
For example, import Angular's `Component` decorator from the `@angular/core` library like this.
|
||||
|
||||
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
|
||||
<code-example path="architecture/src/app/app.component.ts" region="import"></code-example>
|
||||
|
||||
You also import NgModules from Angular *libraries* using JavaScript import statements.
|
||||
For example, the following code imports the `BrowserModule` NgModule from the `platform-browser` library.
|
||||
|
||||
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module" linenums="false"></code-example>
|
||||
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module"></code-example>
|
||||
|
||||
In the example of the simple root module above, the application module needs material from within
|
||||
`BrowserModule`. To access that material, add it to the `@NgModule` metadata `imports` like this.
|
||||
|
||||
<code-example path="architecture/src/app/mini-app.ts" region="ngmodule-imports" linenums="false"></code-example>
|
||||
<code-example path="architecture/src/app/mini-app.ts" region="ngmodule-imports"></code-example>
|
||||
|
||||
In this way you're using the Angular and JavaScript module systems *together*. Although it's easy to confuse the two systems, which share the common vocabulary of "imports" and "exports", you will become familiar with the different contexts in which they are used.
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Introduction to services and dependency injection
|
||||
|
||||
*Service* is a broad category encompassing any value, function, or feature that an app needs.
|
||||
A service is typically a class with a narrow, well-defined purpose.
|
||||
A service is typically a class with a narrow, well-defined purpose.
|
||||
It should do something specific and do it well.
|
||||
|
||||
Angular distinguishes components from services to increase modularity and reusability.
|
||||
@ -14,9 +14,9 @@ in order to mediate between the view (rendered by the template)
|
||||
and the application logic (which often includes some notion of a *model*).
|
||||
|
||||
A component can delegate certain tasks to services, such as fetching data from the server,
|
||||
validating user input, or logging directly to the console.
|
||||
validating user input, or logging directly to the console.
|
||||
By defining such processing tasks in an *injectable service class*, you make those tasks
|
||||
available to any component.
|
||||
available to any component.
|
||||
You can also make your app more adaptable by injecting different providers of the same kind of service,
|
||||
as appropriate in different circumstances.
|
||||
|
||||
@ -28,21 +28,21 @@ available to components through *dependency injection*.
|
||||
|
||||
Here's an example of a service class that logs to the browser console.
|
||||
|
||||
<code-example path="architecture/src/app/logger.service.ts" linenums="false" header="src/app/logger.service.ts (class)" region="class"></code-example>
|
||||
<code-example path="architecture/src/app/logger.service.ts" header="src/app/logger.service.ts (class)" region="class"></code-example>
|
||||
|
||||
Services can depend on other services. For example, here's a `HeroService` that depends on the `Logger` service, and also uses `BackendService` to get heroes. That service in turn might depend on the `HttpClient` service to fetch heroes asynchronously from a server.
|
||||
|
||||
<code-example path="architecture/src/app/hero.service.ts" linenums="false" header="src/app/hero.service.ts (class)" region="class"></code-example>
|
||||
<code-example path="architecture/src/app/hero.service.ts" header="src/app/hero.service.ts (class)" region="class"></code-example>
|
||||
|
||||
## Dependency injection (DI)
|
||||
|
||||
<img src="generated/images/guide/architecture/dependency-injection.png" alt="Service" class="left">
|
||||
|
||||
DI is wired into the Angular framework and used everywhere to provide new components with the services or other things they need.
|
||||
Components consume services; that is, you can *inject* a service into a component, giving the component access to that service class.
|
||||
Components consume services; that is, you can *inject* a service into a component, giving the component access to that service class.
|
||||
|
||||
To define a class as a service in Angular, use the `@Injectable()` decorator to provide the metadata that allows Angular to inject it into a component as a *dependency*.
|
||||
Similarly, use the `@Injectable()` decorator to indicate that a component or other class (such as another service, a pipe, or an NgModule) *has* a dependency.
|
||||
To define a class as a service in Angular, use the `@Injectable()` decorator to provide the metadata that allows Angular to inject it into a component as a *dependency*.
|
||||
Similarly, use the `@Injectable()` decorator to indicate that a component or other class (such as another service, a pipe, or an NgModule) *has* a dependency.
|
||||
|
||||
* The *injector* is the main mechanism. Angular creates an application-wide injector for you during the bootstrap process, and additional injectors as needed. You don't have to create injectors.
|
||||
|
||||
@ -50,19 +50,19 @@ Similarly, use the `@Injectable()` decorator to indicate that a component or oth
|
||||
|
||||
* A *provider* is an object that tells an injector how to obtain or create a dependency.
|
||||
|
||||
For any dependency that you need in your app, you must register a provider with the app's injector,
|
||||
so that the injector can use the provider to create new instances.
|
||||
For any dependency that you need in your app, you must register a provider with the app's injector,
|
||||
so that the injector can use the provider to create new instances.
|
||||
For a service, the provider is typically the service class itself.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
A dependency doesn't have to be a service—it could be a function, for example, or a value.
|
||||
A dependency doesn't have to be a service—it could be a function, for example, or a value.
|
||||
|
||||
</div>
|
||||
|
||||
When Angular creates a new instance of a component class, it determines which services or other dependencies that component needs by looking at the constructor parameter types. For example, the constructor of `HeroListComponent` needs `HeroService`.
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (constructor)" region="ctor"></code-example>
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" header="src/app/hero-list.component.ts (constructor)" region="ctor"></code-example>
|
||||
|
||||
When Angular discovers that a component depends on a service, it first checks if the injector has any existing instances of that service. If a requested service instance doesn't yet exist, the injector makes one using the registered provider, and adds it to the injector before returning the service to Angular.
|
||||
|
||||
@ -78,26 +78,26 @@ The process of `HeroService` injection looks something like this.
|
||||
|
||||
You must register at least one *provider* of any service you are going to use.
|
||||
The provider can be part of the service's own metadata, making that service available everywhere,
|
||||
or you can register providers with specific modules or components.
|
||||
or you can register providers with specific modules or components.
|
||||
You register providers in the metadata of the service (in the `@Injectable()` decorator),
|
||||
or in the `@NgModule()` or `@Component()` metadata
|
||||
or in the `@NgModule()` or `@Component()` metadata
|
||||
|
||||
* By default, the Angular CLI command [`ng generate service`](cli/generate) registers a provider with the root injector for your service by including provider metadata in the `@Injectable()` decorator. The tutorial uses this method to register the provider of HeroService class definition.
|
||||
|
||||
```
|
||||
```
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
```
|
||||
```
|
||||
|
||||
When you provide the service at the root level, Angular creates a single, shared instance of `HeroService`
|
||||
and injects it into any class that asks for it.
|
||||
and injects it into any class that asks for it.
|
||||
Registering the provider in the `@Injectable()` metadata also allows Angular to optimize an app
|
||||
by removing the service from the compiled app if it isn't used.
|
||||
by removing the service from the compiled app if it isn't used.
|
||||
|
||||
* When you register a provider with a [specific NgModule](guide/architecture-modules), the same instance of a service is available to all components in that NgModule. To register at this level, use the `providers` property of the `@NgModule()` decorator,
|
||||
|
||||
```
|
||||
```
|
||||
@NgModule({
|
||||
providers: [
|
||||
BackendService,
|
||||
@ -105,12 +105,12 @@ or in the `@NgModule()` or `@Component()` metadata
|
||||
],
|
||||
...
|
||||
})
|
||||
```
|
||||
```
|
||||
|
||||
* When you register a provider at the component level, you get a new instance of the
|
||||
service with each new instance of that component.
|
||||
service with each new instance of that component.
|
||||
At the component level, register a service provider in the `providers` property of the `@Component()` metadata.
|
||||
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (component providers)" region="providers"></code-example>
|
||||
<code-example path="architecture/src/app/hero-list.component.ts" header="src/app/hero-list.component.ts (component providers)" region="providers"></code-example>
|
||||
|
||||
For more detailed information, see the [Dependency Injection](guide/dependency-injection) section.
|
||||
|
@ -37,13 +37,13 @@ This page demonstrates building a simple _appHighlight_ attribute
|
||||
directive to set an element's background color
|
||||
when the user hovers over that element. You can apply it like this:
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" header="src/app/app.component.html (applied)" region="applied"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.1.html" header="src/app/app.component.html (applied)" region="applied"></code-example>
|
||||
|
||||
{@a write-directive}
|
||||
|
||||
Please note that directives _do not_ support namespaces.
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.avoid.html" linenums="false" header="src/app/app.component.avoid.html (unsupported)" region="unsupported"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.avoid.html" header="src/app/app.component.avoid.html (unsupported)" region="unsupported"></code-example>
|
||||
|
||||
### Write the directive code
|
||||
|
||||
@ -101,7 +101,7 @@ Now edit the generated `src/app/highlight.directive.ts` to look as follows:
|
||||
The `import` statement specifies an additional `ElementRef` symbol from the Angular `core` library:
|
||||
|
||||
You use the `ElementRef` in the directive's constructor
|
||||
to [inject](guide/dependency-injection) a reference to the host DOM element,
|
||||
to [inject](guide/dependency-injection) a reference to the host DOM element,
|
||||
the element to which you applied `appHighlight`.
|
||||
|
||||
`ElementRef` grants direct access to the host DOM element
|
||||
@ -140,12 +140,12 @@ and respond by setting or clearing the highlight color.
|
||||
|
||||
Begin by adding `HostListener` to the list of imported symbols.
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
||||
|
||||
Then add two eventhandlers that respond when the mouse enters or leaves,
|
||||
each adorned by the `HostListener` decorator.
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (mouse-methods)" region="mouse-methods"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (mouse-methods)" region="mouse-methods"></code-example>
|
||||
|
||||
The `@HostListener` decorator lets you subscribe to events of the DOM
|
||||
element that hosts an attribute directive, the `<p>` in this case.
|
||||
@ -166,7 +166,7 @@ The handlers delegate to a helper method that sets the color on the host DOM ele
|
||||
The helper method, `highlight`, was extracted from the constructor.
|
||||
The revised constructor simply declares the injected `el: ElementRef`.
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (constructor)" region="ctor"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (constructor)" region="ctor"></code-example>
|
||||
|
||||
Here's the updated directive in full:
|
||||
|
||||
@ -187,11 +187,11 @@ Currently the highlight color is hard-coded _within_ the directive. That's infle
|
||||
In this section, you give the developer the power to set the highlight color while applying the directive.
|
||||
|
||||
Begin by adding `Input` to the list of symbols imported from `@angular/core`.
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
|
||||
|
||||
Add a `highlightColor` property to the directive class like this:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (highlightColor)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (highlightColor)" region="color"></code-example>
|
||||
|
||||
{@a input}
|
||||
|
||||
@ -204,19 +204,19 @@ Without that input metadata, Angular rejects the binding; see [below](guide/attr
|
||||
|
||||
Try it by adding the following directive binding variations to the `AppComponent` template:
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" header="src/app/app.component.html (excerpt)" region="color-1"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.1.html" header="src/app/app.component.html (excerpt)" region="color-1"></code-example>
|
||||
|
||||
Add a `color` property to the `AppComponent`.
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.1.ts" linenums="false" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.1.ts" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||
|
||||
Let it control the highlight color with a property binding.
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" header="src/app/app.component.html (excerpt)" region="color-2"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.1.html" header="src/app/app.component.html (excerpt)" region="color-2"></code-example>
|
||||
|
||||
That's good, but it would be nice to _simultaneously_ apply the directive and set the color _in the same attribute_ like this.
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||
|
||||
The `[appHighlight]` attribute binding both applies the highlighting directive to the `<p>` element
|
||||
and sets the directive's highlight color with a property binding.
|
||||
@ -225,7 +225,7 @@ That's a crisp, compact syntax.
|
||||
|
||||
You'll have to rename the directive's `highlightColor` property to `appHighlight` because that's now the color property binding name.
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (renamed to match directive selector)" region="color-2"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (renamed to match directive selector)" region="color-2"></code-example>
|
||||
|
||||
This is disagreeable. The word, `appHighlight`, is a terrible property name and it doesn't convey the property's intent.
|
||||
|
||||
@ -237,23 +237,23 @@ Fortunately you can name the directive property whatever you want _and_ **_alias
|
||||
|
||||
Restore the original property name and specify the selector as the alias in the argument to `@Input`.
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (color property with alias)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" header="src/app/highlight.directive.ts (color property with alias)" region="color"></code-example>
|
||||
|
||||
_Inside_ the directive the property is known as `highlightColor`.
|
||||
_Outside_ the directive, where you bind to it, it's known as `appHighlight`.
|
||||
|
||||
You get the best of both worlds: the property name you want and the binding syntax you want:
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||
|
||||
Now that you're binding via the alias to the `highlightColor`, modify the `onMouseEnter()` method to use that property.
|
||||
If someone neglects to bind to `appHighlightColor`, highlight the host element in red:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" header="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" header="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter"></code-example>
|
||||
|
||||
Here's the latest version of the directive class.
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" header="src/app/highlight.directive.ts (excerpt)"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" header="src/app/highlight.directive.ts (excerpt)"></code-example>
|
||||
|
||||
## Write a harness to try it
|
||||
|
||||
@ -263,11 +263,11 @@ lets you pick the highlight color with a radio button and bind your color choice
|
||||
|
||||
Update <code>app.component.html</code> as follows:
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (v2)" region="v2"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (v2)" region="v2"></code-example>
|
||||
|
||||
Revise the `AppComponent.color` so that it has no initial value.
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.ts" linenums="false" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.ts" header="src/app/app.component.ts (class)" region="class"></code-example>
|
||||
|
||||
Here are the harness and directive in action.
|
||||
|
||||
@ -287,12 +287,12 @@ Let the template developer set the default color.
|
||||
|
||||
Add a second **input** property to `HighlightDirective` called `defaultColor`:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (defaultColor)" region="defaultColor"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" header="src/app/highlight.directive.ts (defaultColor)" region="defaultColor"></code-example>
|
||||
|
||||
Revise the directive's `onMouseEnter` so that it first tries to highlight with the `highlightColor`,
|
||||
then with the `defaultColor`, and falls back to "red" if both properties are undefined.
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (mouse-enter)" region="mouse-enter"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" header="src/app/highlight.directive.ts (mouse-enter)" region="mouse-enter"></code-example>
|
||||
|
||||
How do you bind to a second property when you're already binding to the `appHighlight` attribute name?
|
||||
|
||||
@ -300,7 +300,7 @@ As with components, you can add as many directive property bindings as you need
|
||||
The developer should be able to write the following template HTML to both bind to the `AppComponent.color`
|
||||
and fall back to "violet" as the default color.
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (defaultColor)" region="defaultColor"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (defaultColor)" region="defaultColor"></code-example>
|
||||
|
||||
Angular knows that the `defaultColor` binding belongs to the `HighlightDirective`
|
||||
because you made it _public_ with the `@Input` decorator.
|
||||
@ -342,11 +342,11 @@ You can also experience and download the <live-example title="Attribute Directiv
|
||||
In this demo, the `highlightColor` property is an ***input*** property of
|
||||
the `HighlightDirective`. You've seen it applied without an alias:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
||||
|
||||
You've seen it with an alias:
|
||||
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/highlight.directive.ts" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
|
||||
|
||||
Either way, the `@Input` decorator tells Angular that this property is
|
||||
_public_ and available for binding by a parent component.
|
||||
@ -378,7 +378,7 @@ You can tell if `@Input` is needed by the position of the property name in a bin
|
||||
|
||||
Now apply that reasoning to the following example:
|
||||
|
||||
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||
<code-example path="attribute-directives/src/app/app.component.html" header="src/app/app.component.html (color)" region="color"></code-example>
|
||||
|
||||
* The `color` property in the expression on the right belongs to the template's component.
|
||||
The template and its component trust each other.
|
||||
|
@ -106,19 +106,16 @@ To use a directive, component, or pipe in a module, you must do a few things:
|
||||
Those three steps look like the following. In the file where you create your directive, export it.
|
||||
The following example, named `ItemDirective` is the default directive structure that the CLI generates in its own file, `item.directive.ts`:
|
||||
|
||||
<code-example path="bootstrapping/src/app/item.directive.ts" region="directive" header="src/app/item.directive.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="bootstrapping/src/app/item.directive.ts" region="directive" header="src/app/item.directive.ts"></code-example>
|
||||
|
||||
The key point here is that you have to export it so you can import it elsewhere. Next, import it
|
||||
into the NgModule, in this example `app.module.ts`, with a JavaScript import statement:
|
||||
|
||||
<code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" header="src/app/app.module.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" header="src/app/app.module.ts"></code-example>
|
||||
|
||||
And in the same file, add it to the `@NgModule` `declarations` array:
|
||||
|
||||
<code-example path="bootstrapping/src/app/app.module.ts" region="declarations" header="src/app/app.module.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="bootstrapping/src/app/app.module.ts" region="declarations" header="src/app/app.module.ts"></code-example>
|
||||
|
||||
|
||||
Now you could use your `ItemDirective` in a component. This example uses `AppModule`, but you'd do it the same way for a feature module. For more about directives, see [Attribute Directives](guide/attribute-directives) and [Structural Directives](guide/structural-directives). You'd also use the same technique for [pipes](guide/pipes) and components.
|
||||
|
@ -53,7 +53,7 @@ Angular supports most recent browsers. This includes the following specific vers
|
||||
IE
|
||||
</td>
|
||||
<td>
|
||||
11, 10, 9
|
||||
11, 10, 9 ("compatibility view" mode not supported)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -183,7 +183,7 @@ These are the polyfills required to run an Angular application on each supported
|
||||
|
||||
<td>
|
||||
Chrome, Firefox, Edge, <br>
|
||||
Safari, Android, IE10+
|
||||
Safari, Android, IE 10+
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@ -197,7 +197,7 @@ These are the polyfills required to run an Angular application on each supported
|
||||
<tr style="vertical-align: top">
|
||||
|
||||
<td>
|
||||
IE9
|
||||
IE 9
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@ -275,7 +275,7 @@ Some features of Angular may require additional polyfills.
|
||||
</td>
|
||||
|
||||
<td>
|
||||
All but Chrome, Firefox, Edge, IE11 and Safari 10
|
||||
All but Chrome, Firefox, Edge, IE 11 and Safari 10
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
@ -294,7 +294,7 @@ Some features of Angular may require additional polyfills.
|
||||
</td>
|
||||
|
||||
<td>
|
||||
IE10, IE11
|
||||
IE 10, IE 11
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
@ -527,7 +527,7 @@ If you are not using the CLI, add your polyfill scripts directly to the host web
|
||||
|
||||
For example:
|
||||
|
||||
<code-example header="src/index.html" language="html" linenums="false">
|
||||
<code-example header="src/index.html" language="html">
|
||||
<!-- pre-zone polyfills -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
<script src="node_modules/web-animations-js/web-animations.min.js"></script>
|
||||
|
@ -214,14 +214,17 @@ Each budget entry is a JSON object with the following properties:
|
||||
|
||||
<tr>
|
||||
<td>type</td>
|
||||
<td>The type of budget. One of:
|
||||
<td>
|
||||
|
||||
* bundle - The size of a specific bundle.
|
||||
* initial - The initial size of the app.
|
||||
* allScript - The size of all scripts.
|
||||
* all - The size of the entire app.
|
||||
* anyScript - The size of any one script.
|
||||
* any - The size of any file.
|
||||
The type of budget. One of:
|
||||
|
||||
* `bundle` - The size of a specific bundle.
|
||||
* `initial` - The initial size of the app.
|
||||
* `allScript` - The size of all scripts.
|
||||
* `all` - The size of the entire app.
|
||||
* `anyComponentStyle` - This size of any one component stylesheet.
|
||||
* `anyScript` - The size of any one script.
|
||||
* `any` - The size of any file.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -191,7 +191,7 @@ For our example builder, we expect the `options` value to be a `JsonObject` with
|
||||
|
||||
We can provide the following schema for type validation of these values.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example language="json">
|
||||
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
@ -222,7 +222,7 @@ To link our builder implementation with its schema and name, we need to create a
|
||||
|
||||
Create a file named `builders.json` file that looks like this.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example language="json">
|
||||
|
||||
{
|
||||
"builders": {
|
||||
@ -238,7 +238,7 @@ Create a file named `builders.json` file that looks like this.
|
||||
|
||||
In the `package.json` file, add a `builders` key that tells the Architect tool where to find our builder definition file.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example language="json">
|
||||
|
||||
{
|
||||
"name": "@example/command-runner",
|
||||
@ -253,11 +253,11 @@ In the `package.json` file, add a `builders` key that tells the Architect tool w
|
||||
</code-example>
|
||||
|
||||
The official name of our builder is now ` @example/command-runner:command`.
|
||||
The first part of this is the package name (resolved using node resolution), and the second part is the builder name (resolved using the `builder.json` file).
|
||||
The first part of this is the package name (resolved using node resolution), and the second part is the builder name (resolved using the `builders.json` file).
|
||||
|
||||
Using one of our `options` is very straightforward, we did this in the previous section when we accessed `options.command`.
|
||||
|
||||
<code-example format="." language="typescript" linenums="false">
|
||||
<code-example language="typescript">
|
||||
context.reportStatus(`Executing "${options.command}"...`);
|
||||
const child = childProcess.spawn(options.command, options.args, { stdio: 'pipe' });
|
||||
|
||||
@ -274,33 +274,33 @@ The Architect tool uses the target definition to resolve input options for a giv
|
||||
The `angular.json` file has a section for each project, and the "architect" section of each project configures targets for builders used by CLI commands such as 'build', 'test', and 'lint'.
|
||||
By default, for example, the `build` command runs the builder `@angular-devkit/build-angular:browser` to perform the build task, and passes in default option values as specified for the `build` target in `angular.json`.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example language="json">
|
||||
{
|
||||
"myApp": {
|
||||
...
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/myApp",
|
||||
"index": "src/index.html",
|
||||
...
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
...
|
||||
}
|
||||
}
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/myApp",
|
||||
"index": "src/index.html",
|
||||
...
|
||||
},
|
||||
...
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
...
|
||||
}
|
||||
}
|
||||
},
|
||||
...
|
||||
|
||||
</code-example>
|
||||
|
||||
@ -361,7 +361,7 @@ npm install @example/command-runner
|
||||
|
||||
If we create a new project with `ng new builder-test`, the generated `angular.json` file looks something like this, with only default builder configurations.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example language="json">
|
||||
|
||||
{
|
||||
// ...
|
||||
@ -413,21 +413,19 @@ We need to update the `angular.json` file to add a target for this builder to th
|
||||
|
||||
* The configurations key is optional, we'll leave it out for now.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
<code-example language="json">
|
||||
|
||||
{
|
||||
"projects": {
|
||||
"builder-test": {
|
||||
"architect": {
|
||||
"builder-test": {
|
||||
"touch": {
|
||||
"builder": "@example/command-runner:command",
|
||||
"options": {
|
||||
"command": "touch",
|
||||
"args": [
|
||||
"src/main.ts"
|
||||
]
|
||||
}
|
||||
"touch": {
|
||||
"builder": "@example/command-runner:command",
|
||||
"options": {
|
||||
"command": "touch",
|
||||
"args": [
|
||||
"src/main.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
@ -495,16 +493,16 @@ Use integration testing for your builder, so that you can use the Architect sche
|
||||
Here’s an example of a test that runs the command builder.
|
||||
The test uses the builder to run the `ls` command, then validates that it ran successfully and listed the proper files.
|
||||
|
||||
<code-example format="." language="typescript" linenums="false">
|
||||
<code-example language="typescript">
|
||||
|
||||
import { Architect, ArchitectHost } from '@angular-devkit/architect';
|
||||
import { Architect } from '@angular-devkit/architect';
|
||||
import { TestingArchitectHost } from '@angular-devkit/architect/testing';
|
||||
// Our builder forwards the STDOUT of the command to the logger.
|
||||
import { logging, schema } from '@angular-devkit/core';
|
||||
|
||||
describe('Command Runner Builder', () => {
|
||||
let architect: Architect;
|
||||
let architectHost: ArchitectHost;
|
||||
let architectHost: TestingArchitectHost;
|
||||
|
||||
beforeEach(async () => {
|
||||
const registry = new schema.CoreSchemaRegistry();
|
||||
@ -592,4 +590,4 @@ The CLI Builder API provides a new way of changing the behavior of the Angular C
|
||||
|
||||
* We recommend that you use integration tests to test Architect builders. You can use unit tests to validate the logic that the builder executes.
|
||||
|
||||
* If your builder returns an Observable, it should clean up in the teardown logic of that Observable.
|
||||
* If your builder returns an Observable, it should clean up in the teardown logic of that Observable.
|
||||
|
@ -30,7 +30,7 @@ The Filter/Stagger tab in the live example shows a list of heroes with an introd
|
||||
|
||||
The following example demonstrates how to use `query()` and `stagger()` functions on the entry of an animated element.
|
||||
|
||||
* Use `query()` to look for any element entering or leaving the page. The query specifies elements meeting certain CSS class criteria.
|
||||
* Use `query()` to look for an element entering the page that meets certain criteria.
|
||||
|
||||
* For each of these elements, use `style()` to set the same initial style for the element. Make it invisible and use `transform` to move it out of position so that it can slide into place.
|
||||
|
||||
@ -38,7 +38,7 @@ The following example demonstrates how to use `query()` and `stagger()` function
|
||||
|
||||
* Animate each element on screen for 0.5 seconds using a custom-defined easing curve, simultaneously fading it in and un-transforming it.
|
||||
|
||||
<code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="page-animations" language="typescript" linenums="false"></code-example>
|
||||
<code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="page-animations" language="typescript"></code-example>
|
||||
|
||||
## Parallel animation using group() function
|
||||
|
||||
@ -51,7 +51,7 @@ You've seen how to add a delay between each successive animation. But you may al
|
||||
|
||||
In the following example, using groups on both `:enter` and `:leave` allow for two different timing configurations. They're applied to the same element in parallel, but run independently.
|
||||
|
||||
<code-example path="animations/src/app/hero-list-groups.component.ts" region="animationdef" header="src/app/hero-list-groups.component.ts (excerpt)" language="typescript" linenums="false"></code-example>
|
||||
<code-example path="animations/src/app/hero-list-groups.component.ts" region="animationdef" header="src/app/hero-list-groups.component.ts (excerpt)" language="typescript"></code-example>
|
||||
|
||||
## Sequential vs. parallel animations
|
||||
|
||||
@ -74,7 +74,7 @@ The HTML template contains a trigger called `filterAnimation`.
|
||||
|
||||
The component file contains three transitions.
|
||||
|
||||
<code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="filter-animations" language="typescript" linenums="false"></code-example>
|
||||
<code-example path="animations/src/app/hero-list-page.component.ts" header="src/app/hero-list-page.component.ts" region="filter-animations" language="typescript"></code-example>
|
||||
|
||||
The animation does the following:
|
||||
|
||||
@ -101,4 +101,4 @@ You may also be interested in the following:
|
||||
* [Introduction to Angular animations](guide/animations)
|
||||
* [Transition and triggers](guide/transition-and-triggers)
|
||||
* [Reusable animations](guide/reusable-animations)
|
||||
* [Route transition animations](guide/route-animations)
|
||||
* [Route transition animations](guide/route-animations)
|
||||
|
@ -21,8 +21,7 @@ One way to do this is to set the `styles` property in the component metadata.
|
||||
The `styles` property takes an array of strings that contain CSS code.
|
||||
Usually you give it one string, as in the following example:
|
||||
|
||||
<code-example path="component-styles/src/app/hero-app.component.ts" header="src/app/hero-app.component.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="component-styles/src/app/hero-app.component.ts" header="src/app/hero-app.component.ts"></code-example>
|
||||
|
||||
## Style scope
|
||||
|
||||
@ -71,8 +70,7 @@ Use the `:host` pseudo-class selector to target styles in the element that *host
|
||||
targeting elements *inside* the component's template).
|
||||
|
||||
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="host" header="src/app/hero-details.component.css" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="host" header="src/app/hero-details.component.css"></code-example>
|
||||
|
||||
The `:host` selector is the only way to target the host element. You can't reach
|
||||
the host element from inside the component with other selectors because it's not part of the
|
||||
@ -83,8 +81,7 @@ including another selector inside parentheses after `:host`.
|
||||
|
||||
The next example targets the host element again, but only when it also has the `active` CSS class.
|
||||
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="hostfunction" header="src/app/hero-details.component.css" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="hostfunction" header="src/app/hero-details.component.css"></code-example>
|
||||
|
||||
### :host-context
|
||||
|
||||
@ -99,8 +96,7 @@ up to the document root. The `:host-context()` selector is useful when combined
|
||||
The following example applies a `background-color` style to all `<h2>` elements *inside* the component, only
|
||||
if some ancestor element has the CSS class `theme-light`.
|
||||
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="hostcontext" header="src/app/hero-details.component.css" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="hostcontext" header="src/app/hero-details.component.css"></code-example>
|
||||
|
||||
### (deprecated) `/deep/`, `>>>`, and `::ng-deep`
|
||||
|
||||
@ -115,9 +111,7 @@ can bleed into other components.
|
||||
The following example targets all `<h3>` elements, from the host element down
|
||||
through this component to all of its child elements in the DOM.
|
||||
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="deep" header="src/app/hero-details.component.css" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="component-styles/src/app/hero-details.component.css" region="deep" header="src/app/hero-details.component.css"></code-example>
|
||||
|
||||
The `/deep/` combinator also has the aliases `>>>`, and `::ng-deep`.
|
||||
|
||||
@ -304,8 +298,7 @@ Choose from the following modes:
|
||||
|
||||
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
|
||||
|
||||
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts"></code-example>
|
||||
|
||||
`ShadowDom` view encapsulation only works on browsers that have native support
|
||||
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
|
||||
|
@ -12,7 +12,7 @@ A simple example might be a button that sends users to your company website, tha
|
||||
|
||||
Use the Angular CLI to generate a new library skeleton with the following command:
|
||||
|
||||
<code-example format="." language="bash">
|
||||
<code-example language="bash">
|
||||
ng generate library my-lib
|
||||
</code-example>
|
||||
|
||||
@ -35,7 +35,7 @@ The workspace configuration file, `angular.json`, is updated with a project of t
|
||||
|
||||
You can build, test, and lint the project with CLI commands:
|
||||
|
||||
<code-example format="." language="bash">
|
||||
<code-example language="bash">
|
||||
ng build my-lib
|
||||
ng test my-lib
|
||||
ng lint my-lib
|
||||
@ -106,7 +106,7 @@ To learn more, see [Schematics Overview](guide/schematics) and [Schematics for
|
||||
Use the Angular CLI and the npm package manager to build and publish your library as an npm package.
|
||||
Libraries are built in [AoT mode](guide/aot-compiler) by default, so you do not need to specify the `-prod` flag when building for publication.
|
||||
|
||||
<code-example format="." language="bash">
|
||||
<code-example language="bash">
|
||||
ng build my-lib
|
||||
cd dist/my-lib
|
||||
npm publish
|
||||
@ -158,7 +158,7 @@ You don't have to publish your library to the npm package manager in order to us
|
||||
To use your own library in an app:
|
||||
|
||||
* Build the library. You cannot use a library before it is built.
|
||||
<code-example format="." language="bash">
|
||||
<code-example language="bash">
|
||||
ng build my-lib
|
||||
</code-example>
|
||||
|
||||
@ -190,6 +190,6 @@ Every time a file is changed a partial build is performed that emits the amended
|
||||
|
||||
Incremental builds can be run as a backround process in your dev environment. To take advantage of this feature add the `--watch` flag to the build command:
|
||||
|
||||
<code-example format="." language="bash">
|
||||
<code-example language="bash">
|
||||
ng build my-lib --watch
|
||||
</code-example>
|
||||
|
@ -21,18 +21,14 @@ constructor, and lets the framework provide them.
|
||||
|
||||
The following example shows that `AppComponent` declares its dependence on `LoggerService` and `UserContext`.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/app.component.ts" region="ctor" header="src/app/app.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/app.component.ts" region="ctor" header="src/app/app.component.ts"></code-example>
|
||||
|
||||
|
||||
`UserContext` in turn depends on both `LoggerService` and
|
||||
`UserService`, another service that gathers information about a particular user.
|
||||
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/user-context.service.ts" region="injectables" header="user-context.service.ts (injection)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/user-context.service.ts" region="injectables" header="user-context.service.ts (injection)"></code-example>
|
||||
|
||||
|
||||
When Angular creates `AppComponent`, the DI framework creates an instance of `LoggerService` and starts to create `UserContextService`.
|
||||
@ -185,17 +181,13 @@ This `HeroBiosAndContactsComponent` is a revision of `HeroBiosComponent` which y
|
||||
|
||||
Focus on the template:
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="template" header="dependency-injection-in-action/src/app/hero-bios.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="template" header="dependency-injection-in-action/src/app/hero-bios.component.ts"></code-example>
|
||||
|
||||
Now there's a new `<hero-contact>` element between the `<hero-bio>` tags.
|
||||
Angular *projects*, or *transcludes*, the corresponding `HeroContactComponent` into the `HeroBioComponent` view,
|
||||
placing it in the `<ng-content>` slot of the `HeroBioComponent` template.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-bio.component.ts" region="template" header="src/app/hero-bio.component.ts (template)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-bio.component.ts" region="template" header="src/app/hero-bio.component.ts (template)"></code-example>
|
||||
|
||||
The result is shown below, with the hero's telephone number from `HeroContactComponent` projected above the hero description.
|
||||
|
||||
@ -212,9 +204,7 @@ Here's `HeroContactComponent`, which demonstrates the qualifying decorators.
|
||||
|
||||
Focus on the constructor parameters.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="ctor-params" header="src/app/hero-contact.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="ctor-params" header="src/app/hero-contact.component.ts"></code-example>
|
||||
|
||||
The `@Host()` function decorating the `heroCache` constructor property ensures that
|
||||
you get a reference to the cache service from the parent `HeroBioComponent`.
|
||||
@ -299,9 +289,7 @@ whose `nativeElement` property exposes the DOM element for the directive to mani
|
||||
The sample code applies the directive's `myHighlight` attribute to two `<div>` tags,
|
||||
first without a value (yielding the default color) and then with an assigned color value.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/app.component.html" region="highlight" header="src/app/app.component.html (highlight)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/app.component.html" region="highlight" header="src/app/app.component.html (highlight)"></code-example>
|
||||
|
||||
|
||||
The following image shows the effect of mousing over the `<hero-bios-and-contacts>` tag.
|
||||
@ -325,9 +313,7 @@ Angular passes this token to the injector and assigns the result to the paramete
|
||||
The following is a typical example.
|
||||
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="ctor" header="src/app/hero-bios.component.ts (component constructor injection)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="ctor" header="src/app/hero-bios.component.ts (component constructor injection)"></code-example>
|
||||
|
||||
|
||||
Angular asks the injector for the service associated with `LoggerService`
|
||||
@ -386,9 +372,7 @@ You can also use a value provider in a unit test to provide mock data in place o
|
||||
|
||||
The `HeroOfTheMonthComponent` example has two value providers.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-value" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-value" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"></code-example>
|
||||
|
||||
* The first provides an existing instance of the `Hero` class to use for the `Hero` token, rather than
|
||||
requiring the injector to create a new instance with `new` or use its own cached instance.
|
||||
@ -427,9 +411,7 @@ extend the default class, or emulate the behavior of the real class in a test ca
|
||||
|
||||
The following code shows two examples in `HeroOfTheMonthComponent`.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-class" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-class" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"></code-example>
|
||||
|
||||
The first provider is the *de-sugared*, expanded form of the most typical case in which the
|
||||
class to be created (`HeroService`) is also the provider's dependency injection token.
|
||||
@ -448,9 +430,7 @@ Components outside the tree continue to receive the original `LoggerService` ins
|
||||
|
||||
`DateLoggerService` inherits from `LoggerService`; it appends the current date/time to each message:
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/date-logger.service.ts" region="date-logger-service" header="src/app/date-logger.service.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/date-logger.service.ts" region="date-logger-service" header="src/app/date-logger.service.ts"></code-example>
|
||||
|
||||
{@a useexisting}
|
||||
|
||||
@ -472,15 +452,11 @@ You might want to shrink that API surface to just the members you actually need.
|
||||
In this example, the `MinimalLogger` [class-interface](#class-interface) reduces the API to two members:
|
||||
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="src/app/minimal-logger.service.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="src/app/minimal-logger.service.ts"></code-example>
|
||||
|
||||
The following example puts `MinimalLogger` to use in a simplified version of `HeroOfTheMonthComponent`.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.1.ts" header="src/app/hero-of-the-month.component.ts (minimal version)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.1.ts" header="src/app/hero-of-the-month.component.ts (minimal version)"></code-example>
|
||||
|
||||
The `HeroOfTheMonthComponent` constructor's `logger` parameter is typed as `MinimalLogger`, so only the `logs` and `logInfo` members are visible in a TypeScript-aware editor.
|
||||
|
||||
@ -532,9 +508,7 @@ The `runnersUpFactory()` returns the *provider factory function*, which can use
|
||||
the passed-in state value and the injected services `Hero` and `HeroService`.
|
||||
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/runners-up.ts" region="factory-synopsis" header="runners-up.ts (excerpt)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/runners-up.ts" region="factory-synopsis" header="runners-up.ts (excerpt)"></code-example>
|
||||
|
||||
The provider factory function (returned by `runnersUpFactory()`) returns the actual dependency object,
|
||||
the string of names.
|
||||
@ -578,9 +552,7 @@ as the token for a provider of `LoggerService`.
|
||||
|
||||
`MinimalLogger` is an abstract class.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="dependency-injection-in-action/src/app/minimal-logger.service.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" header="dependency-injection-in-action/src/app/minimal-logger.service.ts"></code-example>
|
||||
|
||||
An abstract class is usually a base class that you can extend.
|
||||
In this app, however there is no class that inherits from `MinimalLogger`.
|
||||
@ -606,9 +578,7 @@ Using a class as an interface gives you the characteristics of an interface in a
|
||||
To minimize memory cost, however, the class should have *no implementation*.
|
||||
The `MinimalLogger` transpiles to this unoptimized, pre-minified JavaScript for a constructor function.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" region="minimal-logger-transpiled" header="dependency-injection-in-action/src/app/minimal-logger.service.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" region="minimal-logger-transpiled" header="dependency-injection-in-action/src/app/minimal-logger.service.ts"></code-example>
|
||||
|
||||
Notice that it doesn't have any members. It never grows no matter how many members you add to the class,
|
||||
as long as those members are typed but not implemented.
|
||||
@ -635,15 +605,11 @@ another token that happens to have the same name.
|
||||
You encountered them twice in the *Hero of the Month* example,
|
||||
in the *title* value provider and in the *runnersUp* factory provider.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="provide-injection-token" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="provide-injection-token" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"></code-example>
|
||||
|
||||
You created the `TITLE` token like this:
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="injection-token" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="injection-token" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"></code-example>
|
||||
|
||||
The type parameter, while optional, conveys the dependency's type to developers and tooling.
|
||||
The token description is another developer aid.
|
||||
@ -733,9 +699,7 @@ appear *above* the class definition.
|
||||
|
||||
Break the circularity with `forwardRef`.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="parent-finder.component.ts (AlexComponent providers)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="parent-finder.component.ts (AlexComponent providers)"></code-example>
|
||||
|
||||
|
||||
<!--- Waiting for good examples
|
||||
|
@ -2,16 +2,16 @@
|
||||
|
||||
Application components often need to share information.
|
||||
You can often use loosely coupled techniques for sharing information,
|
||||
such as data binding and service sharing,
|
||||
but sometimes it makes sense for one component to have a direct reference to another component.
|
||||
such as data binding and service sharing,
|
||||
but sometimes it makes sense for one component to have a direct reference to another component.
|
||||
You need a direct reference, for instance, to access values or call methods on that component.
|
||||
|
||||
Obtaining a component reference is a bit tricky in Angular.
|
||||
Angular components themselves do not have a tree that you can
|
||||
Angular components themselves do not have a tree that you can
|
||||
inspect or navigate programmatically. The parent-child relationship is indirect,
|
||||
established through the components' [view objects](guide/glossary#view).
|
||||
|
||||
Each component has a *host view*, and can have additional *embedded views*.
|
||||
Each component has a *host view*, and can have additional *embedded views*.
|
||||
An embedded view in component A is the
|
||||
host view of component B, which can in turn have embedded view.
|
||||
This means that there is a [view hierarchy](guide/glossary#view-hierarchy) for each component,
|
||||
@ -40,18 +40,14 @@ In the following example, the parent `AlexComponent` has several children includ
|
||||
{@a alex}
|
||||
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-1" header="parent-finder.component.ts (AlexComponent v.1)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-1" header="parent-finder.component.ts (AlexComponent v.1)"></code-example>
|
||||
|
||||
|
||||
|
||||
*Cathy* reports whether or not she has access to *Alex*
|
||||
after injecting an `AlexComponent` into her constructor:
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="cathy" header="parent-finder.component.ts (CathyComponent)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="cathy" header="parent-finder.component.ts (CathyComponent)"></code-example>
|
||||
|
||||
|
||||
|
||||
@ -98,17 +94,13 @@ inject its parent via the parent's base class*.
|
||||
The sample's `CraigComponent` explores this question. [Looking back](#alex),
|
||||
you see that the `Alex` component *extends* (*inherits*) from a class named `Base`.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" header="parent-finder.component.ts (Alex class signature)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" header="parent-finder.component.ts (Alex class signature)"></code-example>
|
||||
|
||||
|
||||
|
||||
The `CraigComponent` tries to inject `Base` into its `alex` constructor parameter and reports if it succeeded.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="craig" header="parent-finder.component.ts (CraigComponent)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="craig" header="parent-finder.component.ts (CraigComponent)"></code-example>
|
||||
|
||||
|
||||
|
||||
@ -138,9 +130,7 @@ and add that provider to the `providers` array of the `@Component()` metadata fo
|
||||
{@a alex-providers}
|
||||
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="parent-finder.component.ts (AlexComponent providers)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="parent-finder.component.ts (AlexComponent providers)"></code-example>
|
||||
|
||||
|
||||
[Parent](#parent-token) is the provider's class interface token.
|
||||
@ -149,9 +139,7 @@ The [*forwardRef*](guide/dependency-injection-in-action#forwardref) breaks the c
|
||||
*Carol*, the third of *Alex*'s child components, injects the parent into its `parent` parameter,
|
||||
the same way you've done it before.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="carol-class" header="parent-finder.component.ts (CarolComponent class)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="carol-class" header="parent-finder.component.ts (CarolComponent class)"></code-example>
|
||||
|
||||
|
||||
|
||||
@ -177,9 +165,7 @@ That means he must both *inject* the `Parent` class interface to get *Alice* and
|
||||
|
||||
Here's *Barry*.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="barry" header="parent-finder.component.ts (BarryComponent)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="barry" header="parent-finder.component.ts (BarryComponent)"></code-example>
|
||||
|
||||
|
||||
|
||||
@ -229,9 +215,7 @@ You [learned earlier](guide/dependency-injection-in-action#class-interface) that
|
||||
|
||||
The example defines a `Parent` class interface.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="parent" header="parent-finder.component.ts (Parent class-interface)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="parent" header="parent-finder.component.ts (Parent class-interface)"></code-example>
|
||||
|
||||
|
||||
|
||||
@ -241,9 +225,7 @@ Such a narrow interface helps decouple the child component class from its parent
|
||||
|
||||
A component that could serve as a parent *should* implement the class interface as the `AliceComponent` does.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-class-signature" header="parent-finder.component.ts (AliceComponent class signature)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-class-signature" header="parent-finder.component.ts (AliceComponent class signature)"></code-example>
|
||||
|
||||
|
||||
|
||||
@ -251,9 +233,7 @@ Doing so adds clarity to the code. But it's not technically necessary.
|
||||
Although `AlexComponent` has a `name` property, as required by its `Base` class,
|
||||
its class signature doesn't mention `Parent`.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" header="parent-finder.component.ts (AlexComponent class signature)" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" header="parent-finder.component.ts (AlexComponent class signature)"></code-example>
|
||||
|
||||
|
||||
|
||||
@ -277,21 +257,15 @@ It doesn't in this example *only* to demonstrate that the code will compile and
|
||||
Writing variations of the same parent *alias provider* gets old quickly,
|
||||
especially this awful mouthful with a [*forwardRef*](guide/dependency-injection-in-action#forwardref).
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts"></code-example>
|
||||
|
||||
You can extract that logic into a helper function like the following.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-the-parent" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-the-parent" header="dependency-injection-in-action/src/app/parent-finder.component.ts"></code-example>
|
||||
|
||||
Now you can add a simpler, more meaningful parent provider to your components.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alice-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts"></code-example>
|
||||
|
||||
|
||||
You can do better. The current version of the helper function can only alias the `Parent` class interface.
|
||||
@ -299,14 +273,10 @@ The application might have a variety of parent types, each with its own class in
|
||||
|
||||
Here's a revised version that defaults to `parent` but also accepts an optional second parameter for a different parent class interface.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-parent" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="provide-parent" header="dependency-injection-in-action/src/app/parent-finder.component.ts"></code-example>
|
||||
|
||||
|
||||
And here's how you could use it with a different parent type.
|
||||
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="beth-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false">
|
||||
|
||||
</code-example>
|
||||
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="beth-providers" header="dependency-injection-in-action/src/app/parent-finder.component.ts"></code-example>
|
||||
|
||||
|
@ -68,13 +68,11 @@ using the `Logger` token.
|
||||
Another class, `EvenBetterLogger`, might display the user name in the log message.
|
||||
This logger gets the user from an injected `UserService` instance.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="EvenBetterLogger" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="EvenBetterLogger"></code-example>
|
||||
|
||||
The injector needs providers for both this new logging service and its dependent `UserService`. Configure this alternative logger with the `useClass` provider-definition key, like `BetterLogger`. The following array specifies both providers in the `providers` metadata option of the parent module or component.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-5" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-5"></code-example>
|
||||
|
||||
{@a aliased-class-providers}
|
||||
|
||||
@ -92,13 +90,11 @@ when a component asks for either the new or the old logger.
|
||||
|
||||
If you try to alias `OldLogger` to `NewLogger` with `useClass`, you end up with two different `NewLogger` instances in your app.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6a" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6a"></code-example>
|
||||
|
||||
To make sure there is only one instance of `NewLogger`, alias `OldLogger` with the `useExisting` option.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6b" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6b"></code-example>
|
||||
|
||||
{@a value-provider}
|
||||
|
||||
@ -110,13 +106,11 @@ configure the injector with the `useValue` option
|
||||
|
||||
The following code defines a variable that creates such an object to play the logger role.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="silent-logger" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="silent-logger"></code-example>
|
||||
|
||||
The following provider object uses the `useValue` key to associate the variable with the `Logger` token.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-7" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-7"></code-example>
|
||||
|
||||
{@a non-class-dependencies}
|
||||
|
||||
@ -130,8 +124,7 @@ like the title of the application or the address of a web API endpoint.
|
||||
These configuration objects aren't always instances of a class.
|
||||
They can be object literals, as shown in the following example.
|
||||
|
||||
<code-example path="dependency-injection/src/app/app.config.ts" region="config" header="src/app/app.config.ts (excerpt)" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/app.config.ts" region="config" header="src/app/app.config.ts (excerpt)"></code-example>
|
||||
|
||||
{@a interface-not-valid-token}
|
||||
|
||||
@ -141,11 +134,9 @@ The `HERO_DI_CONFIG` constant conforms to the `AppConfig` interface.
|
||||
Unfortunately, you cannot use a TypeScript interface as a token.
|
||||
In TypeScript, an interface is a design-time artifact, and doesn't have a runtime representation (token) that the DI framework can use.
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9-interface" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9-interface"></code-example>
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-9-ctor-interface" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-9-ctor-interface"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@ -163,22 +154,19 @@ Another solution to choosing a provider token for non-class dependencies is
|
||||
to define and use an `InjectionToken` object.
|
||||
The following example shows how to define such a token.
|
||||
|
||||
<code-example path="dependency-injection/src/app/app.config.ts" region="token" header="src/app/app.config.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/app.config.ts" region="token" header="src/app/app.config.ts"></code-example>
|
||||
|
||||
The type parameter, while optional, conveys the dependency's type to developers and tooling.
|
||||
The token description is another developer aid.
|
||||
|
||||
Register the dependency provider using the `InjectionToken` object:
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9"></code-example>
|
||||
|
||||
Now you can inject the configuration object into any constructor that needs it, with
|
||||
the help of an `@Inject()` parameter decorator.
|
||||
|
||||
<code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" header="src/app/app.component.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" header="src/app/app.component.ts"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@ -215,22 +203,19 @@ who is authorized and who isn't.
|
||||
|
||||
To resolve this, we give the `HeroService` constructor a boolean flag to control display of secret heroes.
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.ts" region="internals" header="src/app/heroes/hero.service.ts (excerpt)" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.ts" region="internals" header="src/app/heroes/hero.service.ts (excerpt)"></code-example>
|
||||
|
||||
You can inject `Logger`, but you can't inject the `isAuthorized` flag. Instead, you can use a factory provider to create a new logger instance for `HeroService`.
|
||||
|
||||
A factory provider needs a factory function.
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="factory" header="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="factory" header="src/app/heroes/hero.service.provider.ts (excerpt)"></code-example>
|
||||
|
||||
Although `HeroService` has no access to `UserService`, the factory function does.
|
||||
You inject both `Logger` and `UserService` into the factory provider
|
||||
and let the injector pass them along to the factory function.
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="provider" header="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="provider" header="src/app/heroes/hero.service.provider.ts (excerpt)"></code-example>
|
||||
|
||||
* The `useFactory` field tells Angular that the provider is a factory function whose implementation is `heroServiceFactory`.
|
||||
|
||||
@ -322,13 +307,13 @@ Thus, services in the NgModule `providers` array or at component level are not t
|
||||
|
||||
The following example of non-tree-shakable providers in Angular configures a service provider for the injector of an NgModule.
|
||||
|
||||
<code-example path="dependency-injection/src/app/tree-shaking/service-and-module.ts" header="src/app/tree-shaking/service-and-modules.ts" linenums="false"> </code-example>
|
||||
<code-example path="dependency-injection/src/app/tree-shaking/service-and-module.ts" header="src/app/tree-shaking/service-and-modules.ts"></code-example>
|
||||
|
||||
You can then import this module into your application module
|
||||
to make the service available for injection in your app,
|
||||
as in the following example.
|
||||
|
||||
<code-example path="dependency-injection/src/app/tree-shaking/app.module.ts" header="src/app/tree-shaking/app.modules.ts" linenums="false"> </code-example>
|
||||
<code-example path="dependency-injection/src/app/tree-shaking/app.module.ts" header="src/app/tree-shaking/app.modules.ts"></code-example>
|
||||
|
||||
When `ngc` runs, it compiles `AppModule` into a module factory, which contains definitions for all the providers declared in all the modules it includes. At runtime, this factory becomes an injector that instantiates these services.
|
||||
|
||||
@ -340,11 +325,11 @@ You can make a provider tree-shakable by specifying it in the `@Injectable()` de
|
||||
|
||||
The following example shows the tree-shakable equivalent to the `ServiceModule` example above.
|
||||
|
||||
<code-example path="dependency-injection/src/app/tree-shaking/service.ts" header="src/app/tree-shaking/service.ts" linenums="false"> </code-example>
|
||||
<code-example path="dependency-injection/src/app/tree-shaking/service.ts" header="src/app/tree-shaking/service.ts"></code-example>
|
||||
|
||||
The service can be instantiated by configuring a factory function, as in the following example.
|
||||
|
||||
<code-example path="dependency-injection/src/app/tree-shaking/service.0.ts" header="src/app/tree-shaking/service.0.ts" linenums="false"> </code-example>
|
||||
<code-example path="dependency-injection/src/app/tree-shaking/service.0.ts" header="src/app/tree-shaking/service.0.ts"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
|
@ -134,7 +134,7 @@ The `@NgModule()` and `@Component()` decorators have the `providers` metadata op
|
||||
|
||||
Components are directives, and the `providers` option is inherited from `@Directive()`. You can also configure providers for directives and pipes at the same level as the component.
|
||||
|
||||
Learn more about [where to configure providers](guide/hierarchical-dependency-injection#where-to-register).
|
||||
Learn more about [where to configure providers](guide/hierarchical-dependency-injection).
|
||||
|
||||
</div>
|
||||
|
||||
@ -196,8 +196,7 @@ Listing dependencies as constructor parameters may be all you need to test appli
|
||||
For example, you can create a new `HeroListComponent` with a mock service that you can manipulate
|
||||
under test.
|
||||
|
||||
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" header="src/app/test.component.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" header="src/app/test.component.ts"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@ -259,8 +258,7 @@ In simple examples, the dependency value is an *instance*, and
|
||||
the class *type* serves as its own lookup key.
|
||||
Here you get a `HeroService` directly from the injector by supplying the `HeroService` type as the token:
|
||||
|
||||
<code-example path="dependency-injection/src/app/injector.component.ts" region="get-hero-service" header="src/app/injector.component.ts" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/injector.component.ts" region="get-hero-service" header="src/app/injector.component.ts"></code-example>
|
||||
|
||||
The behavior is similar when you write a constructor that requires an injected class-based dependency.
|
||||
When you define a constructor parameter with the `HeroService` class type,
|
||||
@ -287,8 +285,7 @@ constructor parameter with `@Optional()`.
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="import-optional">
|
||||
</code-example>
|
||||
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-10-ctor" linenums="false">
|
||||
</code-example>
|
||||
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-10-ctor"></code-example>
|
||||
|
||||
When using `@Optional()`, your code must be prepared for a null value. If you
|
||||
don't register a logger provider anywhere, the injector sets the
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user