Compare commits

..

306 Commits
bazel ... 7.0.2

Author SHA1 Message Date
77f531b6f7 release: cut the v7.0.2 release 2018-10-31 16:05:54 -07:00
3041240cbc build: remove problematic yarn prefix for running bazel 2018-10-31 16:03:29 -07:00
257ac83095 fix(core): Remove static dependency from @angular/core to @angular/compiler (#26734) (#26879) 2018-10-31 13:14:01 -07:00
bc93d47129 build(bazel): remove undeclared dep (#26875)
PR Close #26875
2018-10-31 12:50:28 -04:00
3f61071638 build(bazel): fix bad merge in BUILD file (#26875)
PR Close #26875
2018-10-31 12:50:28 -04:00
ea571aa9d1 build(bazel): generalize fix for AMD name for flat module out file (#26837)
PR Close #26837
2018-10-30 18:37:12 -04:00
40cd0371d2 docs: fixup deployment guide (#26486)
- remove sections that were not relevant (all the development stuff)
- fix incorrect info

PR Close #26486
2018-10-30 16:29:04 -04:00
8356577670 docs: Removing duplicate lines (#26754)
Duplicate lines are removed to avoid confusion.
PR Close #26754
2018-10-30 16:24:51 -04:00
45d3c8093b docs: fix typo (#26776)
PR Close #26776
2018-10-30 16:24:13 -04:00
e7eec2e44b docs: fix typo (#26773)
PR Close #26773
2018-10-30 16:23:49 -04:00
c44b93253c build: use bazel version from node modules (#26691)
* No longer depends on a custom CircleCI docker image that comes with Bazel pre-installed. Since Bazel is now available through NPM, we should be able to use the version from `@bazel/bazel` in order to enforce a consistent environment on CI and locally.
* This also reduces the amount of packages that need to be published (ngcontainer is removed)

PR Close #26691
2018-10-30 16:19:13 -04:00
cd444bc2ba build: Move non-bazel deps to devDependencies (#26691)
This makes yarn_install of ngdeps under Bazel faster, since we don't need many of the large dependencies.
It's important because downstream angular/bazel users will observe the same install time.

PR Close #26691
2018-10-30 16:19:13 -04:00
e9ae26a272 docs: replace unused variable by _ (#26768)
replace unused variable by _  to keep the code consistent between examples

PR Close #26768
2018-10-30 13:49:52 -04:00
f9856974e3 docs: describe your change... (#26784)
PR Close #26784
2018-10-30 13:49:12 -04:00
b3c6409763 fix(core): support computed base class in metadata inheritance (#24014)
PR Close #24014
2018-10-30 13:48:22 -04:00
4c3e9a32d2 docs(changelog): remove reverted fix from 6.1.10 changelog (#26401)
PR Close #26401
2018-10-30 13:47:47 -04:00
2700952040 build: fix ts-api-guardian does not work on windows w/ bazel (#26761)
* Fixes that the `ts-api-guardian` package does not work on Windows with Bazel. This is because `ts-api-guardian` does not resolve the runfiles through theNodeJS `require` function that properly handles runfiles within Bazel.

PR Close #26761
2018-10-30 13:45:58 -04:00
6d92c99c49 build: add option to disable ts-api-guardian default angular tag rules (#26761)
Since the API guardian can be also used by other projects, we should not set up the default Angular project tag rules unless specified explicitly through a given command option (`useAngularTagRules`)

PR Close #26761
2018-10-30 13:45:58 -04:00
7cefb3efd4 docs: configuration file reference (#26484)
PR Close #26484
2018-10-30 13:44:53 -04:00
1c0ab3468d docs: update example dependencies to Angular/CLI/Universal V7 releases (#26820)
PR Close #26820
2018-10-30 13:44:24 -04:00
b5ede01c09 build(docs-infra): move CLI API desciption higher up (#26568)
Closes #26556

PR Close #26568
2018-10-29 13:01:09 -04:00
98b1a9dcfe ci(docs-infra): notify caretaker about aio_monitoring failures (#26649)
PR Close #26649
2018-10-29 13:00:21 -04:00
c277c198d2 test(docs-infra): make redirection tests more robust (#26649)
PR Close #26649
2018-10-29 13:00:21 -04:00
b7d7609872 test(docs-infra): make smoke tests more robust (#26649)
PR Close #26649
2018-10-29 13:00:21 -04:00
415e3e06ed test(docs-infra): fix smoke tests (#26649)
PR Close #26649
2018-10-29 13:00:21 -04:00
0f7a850699 test(docs-infra): run basic smoke tests against PR previews (#26649)
This makes the tests run agaisnt the deployed production versions (as
part of the `aio_monitoring` job) more reliable.

PR Close #26649
2018-10-29 13:00:21 -04:00
1e2525b8a7 test: mark public_api_guard test with fixme-ivy-aot and no-ivy-jit (#26602)
These tests are currently broken because of the following reasons:
- ivy no longer emits a generated index, so the filename of the main d.ts file is different
- ivy currently exports some symbols that don't match the golden file, this needs investigation

PR Close #26602
2018-10-29 12:59:47 -04:00
bc9f534bf4 build: fix the accept binary path in ts-api-guardian error message (#26602)
Fixes #26589

PR Close #26602
2018-10-29 12:59:47 -04:00
ea2a3ca705 build: remove unused @angular/compiler ts-api-guardian golden files (#26602)
these files are not used because the api surface of this package is not considered
to be stable/public api.

the presence of these files only confuses the reader.

PR Close #26602
2018-10-29 12:59:47 -04:00
802e996e64 build: don't depend on npm packages from public api tests (#26602)
We need only the inputs from ng_module.

PR Close #26602
2018-10-29 12:59:47 -04:00
aa7dd1267b docs: add ant design mobile of angular in resources (#26562)
PR Close #26562
2018-10-26 18:10:46 -04:00
91916e7113 docs: fix indentation (#26623)
PR Close #26623
2018-10-26 18:10:15 -04:00
0e92f1eee5 docs: add links to angular subdomains (#26653)
Add link to protactor.angular.io
Replace link from github.com/angular/universal to universal.angular.io
Replace link from github.com/angular/material2 to material.angular.io

fix #18257

PR Close #26653
2018-10-26 18:09:45 -04:00
4ac3b2e2bd build(docs-infra): ensure that CLI code blocks are not auto-linked (#26675)
Some of the text in CLI API docs were being auto-linked to API
pages. This was not correct, and in fact these blocks should not
have any auto links to Angular API at all.

Closes #26570

PR Close #26675
2018-10-26 18:09:21 -04:00
20ce134961 build(docs-infra): mark code blocks to disable auto-linking (#26675)
You can now mark `<code>` blocks with a `no-auto-link` css class
to tell the code auto-linker to ignore this code block.

PR Close #26675
2018-10-26 18:09:21 -04:00
c01f3409f3 fix(compiler): generate relative paths only in summary file errors (#26759)
Previously errors in the summary file would include absolute file names.
This is undesirable as the output of a build should not depend on the
current working directory. Doing so causes nondeterminism issues in
builds.

PR Close #26759
2018-10-26 18:07:55 -04:00
71580c8e37 ci: configure chrome options for protractor (#26735) (#26788)
so that they are more suitable for CI usage.

PR Close #26735

PR Close #26788
2018-10-26 15:46:35 -04:00
e58f8b7be0 ci: mark //modules/benchmarks/src/largetable/render3:perf with fixme-ivy-* tags (#26735) (#26788)
This target fails with odd error that we need to investigate:

[01:19:32] I/direct - Using ChromeDriver directly...
[01:19:32] E/direct - Error code: 135
[01:19:32] E/direct - Error message: Could not find chromedriver at /home/circleci/.cache/bazel/_bazel_circleci/9ce5c2144ecf75d11717c0aa41e45a8d/external/ngdeps/node_modules/webdriver-manager/selenium/chromedriver_2.41. Run 'webdriver-manager update' to download binaries.
[01:19:32] E/direct - Error: Could not find chromedriver at /home/circleci/.cache/bazel/_bazel_circleci/9ce5c2144ecf75d11717c0aa41e45a8d/external/ngdeps/node_modules/webdriver-manager/selenium/chromedriver_2.41. Run 'webdriver-manager update' to download binaries.

PR Close #26735

PR Close #26788
2018-10-26 15:46:35 -04:00
046c96a3f1 ci: use yarn test-ivy-... (#26735) (#26788)
This means that we use the same command to run test on CI as when developing locally.

PR Close #26735

PR Close #26788
2018-10-26 15:46:35 -04:00
00e6569e0f build: fix symbol-extractor by passing through "compile" as environmental variable (#26735) (#26788)
PR Close #26735

PR Close #26788
2018-10-26 15:46:35 -04:00
5dbf9f721b test(ivy): fix or disable failing ivy tests (#26735) (#26788)
These tests were previously not running on CI so they have always been broken,
or got broken just recently :-(.

test(ivy): mark failing test targets with fixme-ivy-jit and fixme-ivy-local tags

PR Close #26735

PR Close #26788
2018-10-26 15:46:35 -04:00
c63bc02846 build: remove ivy build/test tag hackery now that we can (#26735) (#26788)
With https://github.com/bazelbuild/rules_nodejs/pull/388 fixed we can stop messing around
with tags and just rely on the explicitly defined tags.

PR Close #26735

PR Close #26788
2018-10-26 15:46:35 -04:00
2f3308e4f0 docs: rename ivy compile mode 'local' to 'aot' in BAZEL.md (#26735) (#26788)
PR Close #26735

PR Close #26788
2018-10-26 15:46:35 -04:00
cc5e4fb93f ci: move CircleCI env variables definition to shell script (#26786)
PR Close #26786
2018-10-26 13:26:57 -04:00
3ab9947c7f ci: add more info on how CircleCI env vars are defined (#26786)
PR Close #26786
2018-10-26 13:26:57 -04:00
b1f92db22b ci: run Xvfb in the background on CircleCI (#26786)
PR Close #26786
2018-10-26 13:26:57 -04:00
bda1e52b50 build(docs-infra): include inherited members in search index (#26676)
Closes #23800

PR Close #26676
2018-10-26 13:16:33 -04:00
1084ebc091 build(docs-infra): refactor generateKeywords processor (#26676)
PR Close #26676
2018-10-26 13:16:33 -04:00
5a3af00398 ci(docs-infra): split test_and_deploy_aio to two separate jobs (#26746)
By splitting the jobs, if something goes wrong with deploying (e.g. a
network issue), we can re-run just that part instead of having to wait
for all the tests to complete again.

In terms of total duration, the difference should be minimal, because
the two operations (testing and deploying) do not depend on shared
tasks. For example, we need to build again (for the specific target
environment; e.g. stable, next, etc.) before deploying anyway.

PR Close #26746
2018-10-25 21:17:53 -04:00
7a088af3ff build: clean up *.gz files created by payload-size.sh (#26746)
These files are not needed once the size has been calculated and there
is no point in keeping them around.

Deleting them prevents, for example, uploading unnecessary files from
`aio/dist/` to Firebase (because `deploy-to-firebase.sh` runs the
payload size checks right before deploying).

PR Close #26746
2018-10-25 21:17:53 -04:00
3e8d8ec2f5 ci(docs-infra): reduce verbosity of yarn build on CI (#26746)
PR Close #26746
2018-10-25 21:17:53 -04:00
d4ea7f1f7e ci(docs-infra): fix deployment to Firebase (#26746)
Previously, `firebase-tools@3.x` was used and the deployment from
CircleCI failed with `Unexpected error` (HTTP code: 410).

This commit ensures that we use a recent version of `firebase-tools` for
deploying to Firebase. It also ensures that we use the locally installed
`firebase-tools` (not sure where it came from before 😁).

PR Close #26746
2018-10-25 21:17:53 -04:00
23096501e2 build(docs-infra): upgrade cli command docs sources to 4faa81e25 (#26741)
PR Close #26741
2018-10-25 21:10:21 -04:00
023874426e test(upgrade): make e2e tests for upgrade docs examples less flaky (#26726)
PR Close #26726
2018-10-24 19:49:14 -04:00
aeffcdd417 test(elements): make e2e tests for elements docs examples even less flaky (#26726)
PR Close #26726
2018-10-24 19:49:14 -04:00
6d7d7c77e3 ci: only publish builds if relevant aio jobs pass (#26722)
Some of the `aio`-/`docs`-related jobs rely on the locally built Angular
packages. When these jobs fail, it could mean that there is an issue
with the Angular packages (e.g. an unintentional breaking change).

This commit ensures that the `publish_artifacts` job is not run, unless
those `aio`-/`docs`-related jobs pass.

(The `test_aio_tools` job also uses the locally built Angular packages,
but it does not exercise them in a meaningful way to be worth making it
a prerequisite for `publish_artifacts`.)

PR Close #26722
2018-10-24 19:48:41 -04:00
8da6c369e5 build(docs-infra): fix parameter type rendering (#26688)
Closes #24355

PR Close #26688
2018-10-24 19:48:10 -04:00
d0f2bae62b release: cut the v7.0.1 release 2018-10-24 14:07:50 -07:00
062af7a725 ci(docs-infra): fix deployment script (#26731)
PR Close #26731
2018-10-24 13:20:53 -07:00
9d1d70a563 style: format (#26708)
PR Close #26708
2018-10-24 12:13:46 -07:00
5f908eedbf fix(bazel): support --nolegacy_external_runfiles in protractor rule (#26708)
PR Close #26708
2018-10-24 12:13:46 -07:00
a3eac19831 ci: don't publish ivy build artifacts on a non-master branch 2018-10-23 15:27:01 -07:00
cace4dea64 build: rename the ivy compile mode 'local' to 'aot' (#26686)
PR Close #26686
2018-10-23 15:25:42 -07:00
a012ffbd5b build: add test-ivy-jit, test-fixme-ivy-jit, test-ivy-aot and test-fixme-ivy-aot yarn scripts (#26686)
PR Close #26686
2018-10-23 15:23:50 -07:00
2065149d73 ci: build-packages-dist.sh should publish only regular and --compile=local packages (#26471)
We don't need to publish JIT compiled packages as this is not useful for real-world use-cases.

PR Close #26471
2018-10-23 15:23:00 -07:00
44e604b131 build: add source-map-support to various rules within our repo (#26471)
This removes an verbose warning and adds source-mapping support to our build/ci.

Related issue: https://github.com/bazelbuild/rules_nodejs/issues/389

PR Close #26471
2018-10-23 15:22:54 -07:00
4503b28295 build: add aio/node_modules to the .bazelignore file (#26471)
PR Close #26471
2018-10-23 15:22:47 -07:00
f8fcea333f build: remove obsolete files (#26471)
PR Close #26471
2018-10-23 15:22:41 -07:00
a09782b8ac test(ivy): mark failing test targets with fixme-ivy-jit and fixme-ivy-local tags (#26471)
We are close enough to blacklist a few test targets, rather than whitelist targets to run...

Because bazel rules can be composed of other rules that don't inherit tags automatically,
I had to explicitly mark all of our ts_library and ng_module targes with "ivy-local" and
"ivy-jit" tags so that we can create a query that excludes all fixme- tagged targets even
if those targets are composed of other targets that don't inherit this tag.

This is the updated overview of ivy related bazel tags:

- ivy-only: target that builds or runs only under ivy
- fixme-ivy-jit: target that doesn't yet build or run under ivy with --compile=jit
- fixme-ivy-local: target that doesn't yet build or run under ivy with --compile=local
- no-ivy-jit: target that is not intended to build or run under ivy with --compile=jit
- no-ivy-local: target that is not intended to build or run under ivy with --compile=local

PR Close #26471
2018-10-23 15:22:34 -07:00
bfeceb3d3e ci(docs-infra): remove jobs from Travis config (#26377)
PR Close #26377
2018-10-23 14:35:39 -07:00
1a5735d5c0 ci(docs-infra): move deployment to CircleCI (#26377)
PR Close #26377
2018-10-23 14:35:39 -07:00
43d4446ec0 ci: fix payload-size.sh (#26377)
PR Close #26377
2018-10-23 14:35:39 -07:00
91edfb8be0 ci(docs-infra): add jobs to CircleCI config (#26377)
PR Close #26377
2018-10-23 14:35:39 -07:00
9d0a6554a3 build: use CI-provider independent variable names (#26377)
PR Close #26377
2018-10-23 14:35:39 -07:00
8fff438767 test(elements): make e2e tests for elements docs examples less flaky (#26377)
PR Close #26377
2018-10-23 14:35:39 -07:00
b2ae08f272 test(animations): make e2e tests for animations docs examples less flaky (#26377)
PR Close #26377
2018-10-23 14:35:39 -07:00
c78542f124 test(docs-infra): improve logging output in test-pwa-score[-localhost] (#26377)
PR Close #26377
2018-10-23 14:35:38 -07:00
b52c97cf70 ci: disable ivy CI jobs on the patch branch (#26702)
we don't need these jobs to run on the patch branch - this will free up VMs for other jobs

PR Close #26702
2018-10-23 14:32:50 -07:00
929739c736 Revert "feat(router): add prioritizedGuardValue operator optimization and allowing UrlTree return from guard (#26478)" (#26700)
This was incorrectly merged to the 7.0.x patch version branch.

This reverts commit d5fa4dc146.

PR Close #26700
2018-10-23 14:31:43 -07:00
85bde4ff90 ci: re-encrypt .circleci/github_token (#26698)
PR Close #26698
2018-10-23 13:31:49 -07:00
5b5b8254b1 ci: re-encrypt github publish token with recent ngcontainer (#26692)
Something about the docker image changed such that the encrypted value is different

PR Close #26692
2018-10-23 12:00:20 -07:00
ac8871fb7f docs: update npm packages to be accurate for v7 (#26422)
PR Close #26422
2018-10-23 08:58:43 -07:00
6b2b1eae9d docs(service-worker): Specify format of datagroups.cacheConfig.timeout (#26469)
Fixes #26454

PR Close #26469
2018-10-23 08:58:18 -07:00
b3f096219f docs: reorganize events to highlight recent events before older events and move mix to past (#26551)
PR Close #26551
2018-10-23 08:56:53 -07:00
224d9dcd4a docs: add Brian Love to GDE resources (#26594)
PR Close #26594
2018-10-23 08:54:41 -07:00
31a0c2a6c2 build: add config_env_vars = ["compile"] to ngc-wrapped (#26607)
PR Close #26607
2018-10-23 08:53:56 -07:00
c251a5a4d1 build(bazel): fine-grained npm deps and idiomatic install of @angular/bazel (#26607)
PR Close #26607
2018-10-23 08:53:55 -07:00
81e571b908 docs: update release info now that v7 is released (#26660)
PR Close #26660
2018-10-23 08:51:49 -07:00
80a9de0a57 docs(core): fix spelling in ComponentFactory (#26603)
PR Close #26603
2018-10-22 10:38:57 -07:00
d1e2ac86fd build(ivy): fix benchmarks (#26601)
PR Close #26601
2018-10-22 10:36:32 -07:00
9a0d326f4f build: fix ivy package-dist generation (#26629)
PR Close #26629
2018-10-20 21:03:46 -07:00
ce3024017a build(bazel): fix //tools/testing:node target deps (#26629)
PR Close #26629
2018-10-20 21:03:46 -07:00
c8adef2dab build: remove manual tags from platform jasmine tests (#26606)
PR Close #26606
2018-10-19 22:52:12 -07:00
778e1c2602 docs: update animations to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
35bfa1437f docs: update elements to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
4d83078cd2 docs: update upgrade to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
64d005de05 docs: update service-worker to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
0c822b75f9 docs: update router to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
e0a9cfb5e2 docs: update platform-webworker to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
f8dff83d4b docs: update platform-server to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
e411cd124a docs: update platform-browser-dynamic to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
df4e85907c docs: update http with @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
1498dc2dca docs: update forms with @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
abfde44afb docs: update core to use @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
eb9d431487 docs: common with @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
9060fb7031 docs: update animations with @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:55 -07:00
7fbe547f78 docs: update platform-browser with @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:54 -07:00
cda6a215f2 build: update ts-api-guardian jsdoc tag requirements (#26595)
Now `@experimental` tags are banned; and `@publicApi`
tags are required on exports.

PR Close #26595
2018-10-19 14:35:54 -07:00
a8430db45d docs: convert all @experimental tags to @publicApi tags (#26595)
PR Close #26595
2018-10-19 14:35:54 -07:00
5e2bf292e5 feat(docs-infra): rename tagdef: @experimental to @publicApi (#26595)
PR Close #26595
2018-10-19 14:35:54 -07:00
efded24527 feat(docs-infra): remove stable & experimental from status selector (#26595)
PR Close #26595
2018-10-19 14:35:54 -07:00
30ac643d1d build: refactor ts-api-guardian jsdoc tag handling (#26595)
Allow the jsdoc tag processing to be configured by
type (export, member, param) and by action (required,
banned, toCopy).

This is a pre-requisite to moving over to using `@publicApi`
tags rather than `@stable` and `@experimental`.

PR Close #26595
2018-10-19 14:35:54 -07:00
d9725016ad docs: fix release info navigation (#26558)
PR Close #26558
2018-10-19 11:30:39 -07:00
3f94759b14 fix(docs-infra): correct the version of @angular-devkit/build-angular (#26555)
This dependency has not been correctly updated and I had to update it manually.

I think the issue is related to https://github.com/angular/angular-cli/issues/12624 which was fixed between CLI RCs and final.

PR Close #26555
2018-10-19 11:30:12 -07:00
9a46420aaf feat(docs-infra): update to @angular/* v7 (#26555)
PR Close #26555
2018-10-19 11:30:12 -07:00
6a11d7e2a0 docs: add Katerina Skroumpelou to GDE resources (#26547)
PR Close #26547
2018-10-19 11:29:14 -07:00
4fd9988251 build(docs-infra): display github links in CLI API docs (#26515)
This commit includes the following changes:

* CLI version information is read from the CLI package from which
  we read the help files.
* CLI API pages now contain GH links
* line numbers are not shown in GH links, if the doc does not
  have a truthy `startingLine` value. This allows us to remove
  hard coded checks for `guide` pages
* content pages and CLI api docs no longer have a `startingLine`
* the hard-coded `packages` path segment has been removed from
  the templates; instead we now only use the `realProjectRelativePath`.
* the `realProjectRelativePath` has been updated accordingly for API
  and CLI API docs.

PR Close #26515
2018-10-19 11:12:54 -07:00
a4fcd07792 build(docs-infra): show github edit link on CLI overview (#26515)
PR Close #26515
2018-10-19 11:12:54 -07:00
078a928fab docs: forms overview copy edit (#26450)
PR Close #26450
2018-10-19 11:08:48 -07:00
5d90aede4e docs(service-worker): updated browser support for Service Worker (#26408)
PR Close #26408
2018-10-19 11:08:00 -07:00
658a18cdab build(docs-infra): break long CLI options onto two lines (#26272)
PR Close #26272
2018-10-19 11:07:30 -07:00
6d240cf687 build(docs-infra): update CLI option rendering (#26272)
PR Close #26272
2018-10-19 11:07:30 -07:00
dca176e232 build(docs-infra): render CLI arguments consistently (#26272)
In the command syntax, arguments are rendered as
`var`s enclosed in angle brackets. So this is now repeated
in the arguments table too.

PR Close #26272
2018-10-19 11:07:30 -07:00
6c4845515b docs: add release announcement URL 2018-10-18 13:28:45 -07:00
c2ce832f65 fix(ivy): stub TestBed.compileComponents implementation (#26506)
PR Close #26506
2018-10-18 13:28:45 -07:00
c726d27331 ci: add triage PRs config for the ngbot (#26477)
PR Close #26477
2018-10-18 13:28:45 -07:00
c4b7862e1b feat(ivy): i18n compiler support for i18nStart and i18nEnd instructions (#26442)
PR Close #26442
2018-10-18 13:28:45 -07:00
39472e102b feat(ivy): i18n compiler support for element attributes (#26442)
PR Close #26442
2018-10-18 13:28:45 -07:00
1fafc5ca18 feat(ivy): enhance [style] and [class] bindings to be animation aware (#26096)
PR Close #26096
2018-10-18 13:28:45 -07:00
07a26647ac refactor(ivy): move styling files around (#26096)
PR Close #26096
2018-10-18 13:28:44 -07:00
817821e553 fix(ivy): make defineComponent tree shakable by Closure Compiler (#26425)
PR Close #26425
2018-10-18 13:28:44 -07:00
398db3e9f0 test(ivy): enable unit tests for @angular/animations (#26470)
PR Close #26470
2018-10-18 13:28:44 -07:00
d5fa4dc146 feat(router): add prioritizedGuardValue operator optimization and allowing UrlTree return from guard (#26478)
* If all guards return `true`, operator returns `true`
* `false` and `UrlTree` are now both valid returns from a guard
* Both these values wait for higher priority guards to resolve
* Highest priority `false` or `UrlTree` value will be returned

PR Close #26478
2018-10-18 13:28:44 -07:00
0ae3518fa9 refactor(ivy): handle animation metadata normalization in the compiler (#26481)
PR Close #26481
2018-10-18 13:28:44 -07:00
e0f9a1b3f3 build: add more labels to review-pr script (#26493)
PR Close #26493
2018-10-18 13:28:44 -07:00
2604f429c7 build: fix deps for running modules/benchmarks/src/largetable/render3:perf (#26482)
PR Close #26482
2018-10-18 13:28:44 -07:00
ecada17ad4 docs(ivy): i18n design (#26091)
PR Close #26091
2018-10-18 13:28:44 -07:00
fa3751ec9e feat(docs-infra): add v6 to the aio version picker 2018-10-18 12:39:52 -07:00
f85a969219 docs: fix incomplete sentence in CHANGELOG.md 2018-10-18 12:03:23 -07:00
d0a1e42e50 ci: add forms-overview guide to forms approval list (#26549)
PR Close #26549
2018-10-18 12:01:15 -07:00
4f14a09895 docs: fix links to browserlist (#26531)
PR Close #26531
2018-10-18 12:00:38 -07:00
8d28fe9df9 docs: update http to https where possible (#26509)
PR Close #26509
2018-10-18 11:57:57 -07:00
6715f056b0 docs: update links to Karma homepage (#26509)
PR Close #26509
2018-10-18 11:57:57 -07:00
32c018cbfe docs: removing errant double-quote (#26483)
PR Close #26483
2018-10-18 11:57:27 -07:00
a403c4f7f5 docs: type fix (#26386)
according to the source code and the doc https://angular.io/api/forms/NgModel#inherited-from-formsngcontrol-1, the method name should be "viewToModelUpdate" instead of "viewToModel"
PR Close #26386
2018-10-18 11:56:51 -07:00
bf656d64b8 release: cut the v7.0.0 release 2018-10-18 10:50:41 -07:00
3b183ce9b5 build(docs-infra): allow "" as empty region in {@example} tags (#26514)
PR Close #26514
2018-10-18 09:54:17 -07:00
f635c3ecec build(docs-infra): only render code example content in one place (#26514)
PR Close #26514
2018-10-18 09:54:17 -07:00
dd6e8424aa build(docs-infra): throw error if using title on code snippets (#26514)
Since #26396, the `title` property is ignored and `header` should be
used instead for specifying a code snippet's header.

This commit ensures that we don't accidentally set `title` have it be
silently ignored.

PR Close #26514
2018-10-18 09:54:17 -07:00
1035c6a3ee build(docs-infra): update git ref for cli command docs (#26545)
This is to get the latest changes done in https://github.com/angular/angular-cli/pull/12634

PR Close #26545
2018-10-18 09:54:00 -07:00
b49b274a16 fix(aio): add relative to app level routes section (#26504)
Added word *relative* to the **Routes at the app level** section description. This was not specified before. The routes in the *lazy-loading-ngmodules/src/app/app-routing.module.ts* also had `loadChildren` values starting with `app/...`.

The code for `app-routing.module.ts` is already fixed in [this commit](67ad9468d3)
PR Close #26504
2018-10-17 13:11:43 -07:00
a4ebf3fb6d docs: fix formatting of PULL_REQUEST_TEMPLATE.md (#26512)
This change enables developers to check the checkboxes or update them
after they submitted a PR.

PR Close #26512
2018-10-17 13:09:45 -07:00
9997ab5ef9 build(docs-infra): update git ref for cli command docs (#26497)
Update for version 7 release

PR Close #26497
2018-10-17 11:24:20 -07:00
c109aada2c docs: Update link to angular-cli repo (#26497)
PR Close #26497
2018-10-17 11:24:20 -07:00
57ce13aa1c docs: update contributing page (#26497)
PR Close #26497
2018-10-17 11:24:20 -07:00
2fd127d000 docs: update continuous integration story (#26497)
PR Close #26497
2018-10-17 11:24:20 -07:00
2f28e6a62d docs: replace alert-is-helpful with alert is-helpful (#26497)
PR Close #26497
2018-10-17 11:24:20 -07:00
bf1a13e5e1 docs: add missing backticks (#26497)
PR Close #26497
2018-10-17 11:24:20 -07:00
ab9e114fee docs: remove for example code (#26519)
PR Close #26519
2018-10-17 11:23:51 -07:00
448ab9c465 docs: edit file structure guide (#26256)
PR Close #26256
2018-10-17 11:08:37 -07:00
d769b441c0 docs: change links to cli wiki to link to new aio docs (#26489)
PR Close #26489
2018-10-17 11:06:35 -07:00
50ccbe744d docs: change links to cli wiki to link to new aio docs files m to z (#26492)
PR Close #26492
2018-10-17 11:06:07 -07:00
b29e709208 fix(docs-infra): rename "title" by "header" to avoid unwanted tooltips (#26396)
Closes #26174

PR Close #26396
2018-10-17 11:05:30 -07:00
017a087f9b fix(docs-infra): don't hide contributor links on devices that cannot hover (#26410)
Fixes #16690

PR Close #26410
2018-10-17 11:04:35 -07:00
4b522572e6 fix(docs-infra): fix top menu logo position (#26473)
Fixes #26468

PR Close #26473
2018-10-17 11:03:24 -07:00
3808434eec build(docs-infra): do not add extra space after links in tables (#26505)
Closes #26487

PR Close #26505
2018-10-17 11:02:56 -07:00
34aff0b3a1 docs(forms): change headings (#25900)
Update heading level so it will appear in the TOC.
PR Close #25900
2018-10-16 20:39:46 -07:00
7cb4183f58 docs(forms): change headings (#25900)
Remove "Form" sub-heading & move intro to template-driven form heading.
PR Close #25900
2018-10-16 20:39:46 -07:00
960d32dd4f docs(forms): change headings (#25900)
Change the headings of the template-driven forms guide page.

This makes the first heading consistent with other guide pages and the menu label reducing confusion to users browsing the guide.
PR Close #25900
2018-10-16 20:39:45 -07:00
be0382b50c docs: fix links to setup and cli docs (#26463)
PR Close #26463
2018-10-16 14:14:19 -07:00
7ac4b76336 docs: remove setup for local dev and anatomy of setup docs from nav (#26380)
PR Close #26380
2018-10-16 14:14:00 -07:00
00b5c7b49b fix(service-worker): clean up caches from old SW versions (#26319)
Since the SW immediately takes over all clients, it is safe to delete
caches used by older (e.g. beta) `@angular/service-worker` versions to
avoid running into browser storage quota limitations.

PR Close #26319
2018-10-16 14:12:08 -07:00
96f38562bd docs: overview for cli reference section (#26043)
PR Close #26043
2018-10-16 14:11:26 -07:00
94b98aa819 docs: updated text to match the Getting started guide (#26421)
PR Close #26421
2018-10-16 14:11:12 -07:00
1c9b06504b fix(router): fix regression where navigateByUrl promise didn't resolve on CanLoad failure (#26455)
Fixes #26284

PR Close #26455
2018-10-15 16:53:25 -07:00
dd8a85158e docs: Indicate that PRs should have an associated issue (#25436)
PR Close #25436
2018-10-15 16:51:46 -07:00
164f79a7b0 style: typos in TS 3.1 integration test (#26433)
The test was mentionning TS 3.0.

PR Close #26433
2018-10-15 16:48:44 -07:00
327c614799 test(docs-infra): improve logging output in test-pwa-score[-localhost] (#26459)
PR Close #26459
2018-10-15 15:23:36 -07:00
1aa8cfbf74 build(docs-infra): upgrade lighthouse to 3.2.1 (#26459)
PR Close #26459
2018-10-15 15:23:36 -07:00
95d0626a1e ci(docs-infra): reduce flakyness (#26459)
PR Close #26459
2018-10-15 15:23:36 -07:00
5183bbffbe docs: update process for cli tool and restructure doc (#25752)
PR Close #25752
2018-10-15 11:22:18 -07:00
e76a570908 refactor(ivy): remove LNode (#26426)
PR Close #26426
2018-10-15 11:20:32 -07:00
9afc9a7464 docs: minor wording correction. "use" to "user". (#26452)
PR Close #26452
2018-10-15 11:19:46 -07:00
931e603f80 refactor(ivy): revert LNode.data into LViewData[HOST] (#26424)
PR Close #26424
2018-10-15 10:17:12 -07:00
45732e5b91 fix(ivy): fix reference to pipeBind instruction with 2 args (#26451)
PR Close #26451
2018-10-15 10:14:25 -07:00
b2db32b715 docs: getting started updated for accuracy and style (#26093)
PR Close #26093
2018-10-12 14:16:02 -07:00
9e32dc7c95 build: upgrade @types/jasminewd2 to 2.0.4 (#26139)
This commit also removes the extra jasminewd2 typings, since the changes
have been merged in the official typings with
DefinitelyTyped/DefinitelyTyped#28957.

PR Close #26139
2018-10-12 14:11:11 -07:00
a19b690338 docs: move cli commands above api in nav (#26405)
PR Close #26405
2018-10-12 14:09:39 -07:00
bab5b68910 fix(docs-infra): prevent unnecessary SideNav scrollbar (#26416)
Fixes #21508

PR Close #26416
2018-10-12 14:09:09 -07:00
3daeadd235 docs: visual studio removed from nav and updated to refer to getting started instead of quickstart repo (#26376)
PR Close #26376
2018-10-12 14:08:11 -07:00
ff15043e48 fix(core): allow null value for renderer setElement(…) (#17065)
Using Renderer’s setElementAttribute or setElementStyle with a null or undefined value removes the
corresponding attribute or style. The argument type should allow this when using strictNullChecks.

Closes #13686

PR Close #17065
2018-10-12 09:17:59 -07:00
ea20ae63d0 build(docs-infra): only show name in 'inherited from' section (#26387)
Closes #26181

PR Close #26387
2018-10-12 09:13:02 -07:00
7777a99fe5 fix(docs-infra): highlight current CLI command in navigation menu (#26388)
Previously CLI was being treated like the API page, where the top level item
had to be highlighted for any command page. But now the CLI commands all
have their own navigation item, which can be selected, so there is no need
to special case CLI paths any more.

Closes #26373

PR Close #26388
2018-10-12 09:02:11 -07:00
9ebb4c02a2 docs(ivy): update status.md (#26382)
PR Close #26382
2018-10-12 09:01:41 -07:00
7fbeb04b7c build(docs-infra): upgrade @angular/material to 7.0.0-rc.1 (#26394)
PR Close #26394
2018-10-12 08:55:15 -07:00
42ee50fc22 build(docs-infra): upgrade @angular/* to 7.0.0-rc.1 (#26394)
PR Close #26394
2018-10-12 08:55:15 -07:00
163b7c94a9 build(docs-infra): upgrade @angular/cli to 7.0.0-rc.2 (#26394)
PR Close #26394
2018-10-12 08:55:15 -07:00
071934e92a fix(upgrade): properly destroy upgraded component elements and descendants (#26209)
Fixes #26208

PR Close #26209
2018-10-11 21:07:48 -07:00
735dfd3b1a refactor(ivy): replace LNode.dynamicLContainerNode with flat LContainers (#26407)
PR Close #26407
2018-10-11 21:07:21 -07:00
70cd112872 refactor(ivy): remove TNode.dynamicContainerNode (#26407)
PR Close #26407
2018-10-11 21:07:21 -07:00
989555352d build: add --force to push-pr 2018-10-11 16:13:59 -07:00
99736750fc docs: add angularmix to events page (#26374)
PR Close #26374
2018-10-11 14:16:02 -07:00
0a3f8173f0 refactor(platform-browser): remove type assertion on console.profileEnd (#26303)
Since typescript v3.1 type definition for console.profileEnd is fixed and type assertion 'any' is
not needed any more

PR Close #26303
2018-10-11 14:12:23 -07:00
6a64ac4151 fix(ivy): Renderer2 should not use a special injection fn (#26369)
PR Close #26369
2018-10-11 14:12:03 -07:00
062fe5c2cf docs: fix transpiles link in dependency injection (#26250)
fixed a double bracket that broke the link

PR Close #26250
2018-10-11 14:11:45 -07:00
4b494f23f5 fix(ivy): fix generated code for style bindings with units (#26397)
PR Close #26397
2018-10-11 14:11:15 -07:00
bd186c7ef9 docs: move angularjs and add performance to nav (#26375)
PR Close #26375
2018-10-11 14:10:41 -07:00
1657c997cd docs: fix tbd link and minor edits (#26404)
PR Close #26404
2018-10-11 14:10:01 -07:00
1e69d601fb fix(ivy): ensure that ɵNgModuleDefWithMeta is exported (#26082)
This is needed to build an app with `ngtsc` once `ngcc` has compiled
`@angular/core`.

PR Close #26082
2018-10-11 14:08:39 -07:00
34b6d5fff9 refactor(ivy): ngcc - Transformer delegates to Analyzers and Renderer (#26082)
PR Close #26082
2018-10-11 14:08:39 -07:00
632f66a461 refactor(ivy): ngcc - Renderer now manages d.ts transformation (#26082)
PR Close #26082
2018-10-11 14:08:39 -07:00
f7b17a4784 refactor(ivy): ngcc - DecorationAnalyzer acts on whole program (#26082)
PR Close #26082
2018-10-11 14:08:39 -07:00
9562324ea4 refactor(ivy): implement ngcc SwitchMarkerAnalyzer (#26082)
PR Close #26082
2018-10-11 14:08:39 -07:00
880c0add56 refactor(ivy): move and rename Analyzer to DecorationAnalyzer (#26082)
This is in preparation for adding in other kinds of Analyzer.

PR Close #26082
2018-10-11 14:08:39 -07:00
64c96186da refactor(ivy): move ngcc rootDirs computation into a function (#26082)
PR Close #26082
2018-10-11 14:08:39 -07:00
26209fca49 refactor(ivy): remove ngcc Parser and use NgccReflectionHost instead (#26082)
PR Close #26082
2018-10-11 14:08:39 -07:00
7f03528dbc refactor(ivy): implement NgccReflectionHost.findDecoratedFiles (#26082)
PR Close #26082
2018-10-11 14:08:39 -07:00
d17602f31d refactor(ivy): rename and move ngcc Parsed... to Decorated... (#26082)
PR Close #26082
2018-10-11 14:08:39 -07:00
7d0e17530b ci(docs-infra): allow aio_local builds to fail on Travis (#26366)
This job is flaky (up to 50%!) so let's allow it to fail while
we investigate the reason.

PR Close #26366
2018-10-11 13:38:59 -07:00
053bf27fb3 refactor(ivy): use context discovery in TestBed implementation (#26211)
PR Close #26211
2018-10-11 13:01:28 -07:00
39f42bad1c feat(ivy): i18n compiler support for element attributes (#26280)
PR Close #26280
2018-10-11 13:00:19 -07:00
3f8ac238f1 refactor(ivy): remove unused directives field from TView (#26364)
It was removed in #26316

PR Close #26364
2018-10-11 12:59:02 -07:00
e0e2038718 build(docs-infra): pin git ref for cli command docs (#26391)
The JSON files from which cli command docs for angular.io are generated
is broken on master (e.g. angular/cli-builds@e0ec86757), which cause foc
generation (and CI) to fail.

Pinning the git ref where we pull cli sources from to a version that is
known to be working (until we figure out what the best approach is)

PR Close #26391
2018-10-11 12:57:49 -07:00
67608a907e build(docs-infra): make the git ref for cli command docs configurable (#26391)
PR Close #26391
2018-10-11 12:57:49 -07:00
7acdad6921 release: cut the v7.0.0-rc.1 release 2018-10-10 15:04:08 -07:00
7466a99dda Revert "fix(upgrade): properly destroy upgraded component elements and descendants (#26209)"
This reverts commit 912f3d186f. Revert is needed due to compilation failures due to this PR inside Google.
2018-10-10 14:44:52 -07:00
912f3d186f fix(upgrade): properly destroy upgraded component elements and descendants (#26209)
Fixes #26208

PR Close #26209
2018-10-10 14:19:00 -07:00
e26cb21e4e docs: release notes for the v release 2018-10-10 11:46:39 -07:00
be4edf15ee fix(core): resolving merge conflicts in query.ts (#26324)
PR Close #26324
2018-10-09 17:34:08 -07:00
d5e9405d4f fix(ivy): local refs in View and Content Queries should be pulled out into consts in generated code (#26240)
PR Close #26240
2018-10-09 17:20:36 -07:00
d1b7bb52e7 docs: add note for including polyfills for StackBlitz examples (#25892)
PR Close #25892
2018-10-09 17:04:20 -07:00
1312693f88 docs: add core-js polyfills for StackBlitz support (#25892)
PR Close #25892
2018-10-09 17:04:20 -07:00
72ff9c880c docs: sync boilerplate configuration with Angular CLI RC2 (#25892)
Revers Jasmine version back to ~2.99.1

PR Close #25892
2018-10-09 17:04:20 -07:00
3060b3e29b docs: bump Jasmine version, fix build scripts (#25892)
PR Close #25892
2018-10-09 17:04:20 -07:00
ee28b64d74 docs: add webpack-cli back in shared example dependencies (#25892)
PR Close #25892
2018-10-09 17:04:20 -07:00
1246ba53c7 docs: cleanup universal boilerplate scripts (#25892)
PR Close #25892
2018-10-09 17:04:20 -07:00
c29ff722a0 docs: add testing styles back to boilerplate configuration (#25892)
PR Close #25892
2018-10-09 17:04:20 -07:00
67ad9468d3 docs: fix broken lazy loading examples with Angular CLI RC upgrade (#25892)
PR Close #25892
2018-10-09 17:04:19 -07:00
f922808b8d docs: update to latest Angular RC, CLI RC, and Jasmine releases (#25892)
PR Close #25892
2018-10-09 17:04:19 -07:00
67435d456c Revert "docs: add testing styles in index.html, remove additional configuration" (#25892)
This reverts commit 621d82a44c9d46f69f3296b302984f5949b8dee8.

PR Close #25892
2018-10-09 17:04:19 -07:00
fbfce79b93 docs: add testing styles in index.html, remove additional configuration (#25892)
PR Close #25892
2018-10-09 17:04:19 -07:00
2a14dfa4ba docs: update shared example dependencies to Angular 7 and CLI 7 (#25892)
PR Close #25892
2018-10-09 17:04:19 -07:00
8e71ad6027 docs: typo on function name for handleError() (#26261)
changed function name `errorHandle()` to `handleError()`
PR Close #26261
2018-10-09 16:54:15 -07:00
25289664ea docs: fix sentence in attribute directives guide (#26266)
PR Close #26266
2018-10-09 16:53:42 -07:00
e5644204dc fix(ivy): removing unnecessary assert in getOrCreateNodeInjector function (#26305)
PR Close #26305
2018-10-09 16:52:00 -07:00
69b9758ab8 fix(ivy): removing no longer needed QueryReadType (#26314) (#26314)
PR Close #26314

PR Close #26314
2018-10-09 16:50:34 -07:00
7ea5161d4d refactor(ivy): merge directives into LViewData (#26316)
PR Close #26316
2018-10-09 16:46:00 -07:00
b0879046b7 test(ivy): add testing utility to replace loadDirective (#26316)
PR Close #26316
2018-10-09 16:46:00 -07:00
456f23f76a fix(ivy): reflect animations field directly into the output definition (#26322)
The 'animations' field of @Component metadata should be copied directly
into the ngComponentDef for that component and should not pass through
static resolution.

Previously the animations array was statically resolved and then the
values were translated back when generating ngComponentDef.

PR Close #26322
2018-10-09 16:45:31 -07:00
9623e7c639 Revert "fix(upgrade): properly destroy upgraded component elements and descendants (#26209)"
This reverts commit 5a31bde649.
2018-10-08 14:34:47 -07:00
83302d193e fix(ivy): ensure ngcc compiles @angular/core with correct internal imports (#26236)
PR Close #26236
2018-10-08 13:45:46 -07:00
807070fe83 refactor(ivy): ngcc - expose the package name from EntryPoint (#26236)
PR Close #26236
2018-10-08 13:45:46 -07:00
3ac8a63499 test(ivy): update ngcc integration test (#26236)
PR Close #26236
2018-10-08 13:45:46 -07:00
6a24db2bc6 fix(ivy): ngcc: only consider decorators from @angular/core (#26236)
PR Close #26236
2018-10-08 13:45:46 -07:00
50d1cba174 fix(ivy): ngcc: remove redundant __decorate() calls (#26236)
Previously we only removed assignments to `Class.decorators = [];`
if the array was not empty.

Now we also remove calls to `__decorate([])`, similarly.

PR Close #26236
2018-10-08 13:45:46 -07:00
44c05c05af fix(ivy): include "variable-declared" decorated classes in ngcc compilation (#26236)
Previously, classes that were declared via variable declarations,
rather than class declarations, were being excluded from the
parsed classes.

PR Close #26236
2018-10-08 13:45:46 -07:00
7d08722e80 fix(ivy): support tsutils.__decorate decorator declarations in ngcc (#26236)
The most recent Angular distributions have begun to use __decorate instead of Class.decorators.
This prevents `ngcc` from recognizing the classes and then fails to perform the transform to
ivy format.

Example:

```
var ApplicationModule = /** @class */ (function () {
    // Inject ApplicationRef to make it eager...
    function ApplicationModule(appRef) {
    }
    ApplicationModule = __decorate([
        NgModule({ providers: APPLICATION_MODULE_PROVIDERS }),
        __metadata("design:paramtypes", [ApplicationRef])
    ], ApplicationModule);
    return ApplicationModule;
}());
```

Now `ngcc` recognizes `__decorate([...])` declarations and performs its transform.

See FW-379

PR Close #26236
2018-10-08 13:45:46 -07:00
13cdd13511 fix(ivy): support late-initialized variables in ngcc/ngtsc (#26236)
In some formats variables are declared as `var` or `let` and only
assigned a value later in the code.

The ngtsc resolver still needs to be able to resolve this value,
so the host now provides a `host.getVariableValue(declaration)`
method that can do this resolution based on the format.

The hosts make some assumptions about the layout of the
code, so they may only work in the constrained scenarios that
ngcc expects.

PR Close #26236
2018-10-08 13:45:46 -07:00
9320ec0f43 build(docs-infra): upgrade Angular to 7.0.0-rc.0 and TypeScript to 3.1.1 (#26202)
PR Close #26202
2018-10-08 13:43:31 -07:00
5dd225cb43 build(docs-infra): upgrade webpack-cli to 3.1.2 (#26202)
This is necessary to avoid webpack/webpack#8082, when installing
dependencies without taking the lockfile into account (e.g. with
`yarn aio-use-local` - locally or on CI).

PR Close #26202
2018-10-08 13:43:31 -07:00
1b1c8ee545 ci(docs-infra): run tests against local Angular packages too (#26202)
PR Close #26202
2018-10-08 13:43:31 -07:00
10e414f617 test(docs-infra): fix tests (#26202)
PR Close #26202
2018-10-08 13:43:31 -07:00
b46fa92ae5 ci(docs-infra): remove unnecessary command (#26202)
This was accidentally merged with 4d506acba and 87f60bccf.
The build script is called in `scripts/ci/build.sh` (if necessary).

PR Close #26202
2018-10-08 13:43:31 -07:00
0bdea1f69c docs: update docs to reflect the changes in RxJS 6 (#26238)
PR Close #26238
2018-10-08 13:43:12 -07:00
5a31bde649 fix(upgrade): properly destroy upgraded component elements and descendants (#26209)
Fixes #26208

PR Close #26209
2018-10-08 12:06:13 -07:00
decc0b840d ci(docs-infra): re-use env variable (#26138)
PR Close #26138
2018-10-08 12:01:02 -07:00
55d54c7e97 fix(platform-browser): fix #22155, destroy hammer manager when off (#22156)
PR Close #22156
2018-10-05 15:44:05 -07:00
ccceff5ecc docs: add fakeAsync test new feature document (#23117)
PR Close #23117
2018-10-05 15:43:37 -07:00
6c6bc95ac0 docs: Rename 'QuickStart' into 'Getting Started' (#25762)
Delete symlink

docs: Undo unwanted changes

docs: Rename 'QuickStart' into 'Getting Started'

Revert symlink commit
PR Close #25762
2018-10-05 15:43:16 -07:00
c9cfcfa728 docs: clarify CurrencyPipe display property (#25852)
Clarify how to suppress the currency/code in the CurrencyPipe by passing an empty string.

PR Close #25852
2018-10-05 15:42:57 -07:00
f543d71cc3 docs: add package doc files (#26047)
PR Close #26047
2018-10-05 15:42:14 -07:00
3a5cb1cb11 fix(docs-infra): fix positioning of message for disabled JavaScript (#26198)
PR Close #26198
2018-10-05 15:39:23 -07:00
ab6f055479 ci(docs-infra): show custom 404 page on preview server (for consistency) (#26199)
PR Close #26199
2018-10-05 15:39:02 -07:00
3683c6a188 docs: fix wording (#26207)
fix wording to sound better
PR Close #26207
2018-10-05 14:19:08 -07:00
4006c9b6e6 docs: fix spelling errors (#26213)
PR Close #26213
2018-10-05 14:18:19 -07:00
245b85f72a docs: typo fixes (#26247)
PR Close #26247
2018-10-05 14:00:20 -07:00
bfeed842ee docs(service-worker): improve API docs for SwPush/SwUpdate (#23138)
PR Close #23138
2018-10-05 13:48:14 -07:00
77942cc690 refactor(service-worker): simplify/improve NgswCommChannel typings (#23138)
PR Close #23138
2018-10-05 13:48:14 -07:00
7aed64d3a1 docs(service-worker): add UpdateActivated/AvailableEvent to the public API (#23138)
PR Close #23138
2018-10-05 13:48:14 -07:00
9953fe7c00 fix(ivy): reexport compileNgModuleFactory__POST_NGCC__ to prevent DCE in FESM (#26071)
While creating FESM files, rollup usually drops all unused symbols.
All *__POST_NGCC__ are unused unless ngcc rewires stuff. To prevent this DCE
we reexport them as private symbols. If ngcc is not used, these symbols will
be dropped when we optimize an application bundle.

PR Close #26071
2018-10-05 13:45:55 -07:00
3cce4afa0d build(docs-infra): update fsevents to 1.2.4 to support node 10 (#26218)
PR Close #26218
2018-10-05 13:45:36 -07:00
8f25321787 refactor(ivy): update context discovery to prep for dir merge (#26262)
PR Close #26262
2018-10-05 13:39:30 -07:00
51dfdd5dd1 fix(ivy): sync view with blueprint when necessary (#26263)
PR Close #26263
2018-10-05 13:39:03 -07:00
fdaf573073 feat(ivy): expose node injector as part of debug context (#26210)
PR Close #26210
2018-10-04 10:12:02 -07:00
35bf95281f test(ivy): implement tests for template type-checking (#26203)
This commit builds on the NgtscTestEnvironment helper work before and
introduces template_typecheck_spec.ts, which contains compiler tests
for template type-checking.

PR Close #26203
2018-10-04 10:11:17 -07:00
7a78889994 test(ivy): refactor ngtsc tests to use an NgtscTestEnvironment helper (#26203)
This commit gets ready for the introduction of ngtsc template
type-checking tests by refactoring test environment setup into a
custom helper. This helper will simplify the authoring of future
ngtsc tests.

Ngtsc tests previously returned a numeric error code (a la ngtsc's CLI
interface) if any TypeScript errors occurred. The helper has the
ability to run ngtsc and return the actual array of ts.Diagnostics, which
greatly increases the ability to write clean tests.

PR Close #26203
2018-10-04 10:11:17 -07:00
19c4e705ff feat(ivy): turn on template type-checking via fullTemplateTypeCheck (#26203)
This commit enables generation and checking of a type checking ts.Program
whenever the fullTemplateTypeCheck flag is enabled in tsconfig.json. It
puts together all the pieces built previously and causes diagnostics to be
emitted whenever type errors are discovered in a template.

Todos:

* map errors back to template HTML
* expand set of type errors covered in generated type-check blocks

PR Close #26203
2018-10-04 10:11:17 -07:00
36d6e6076e feat(ivy): support template type check narrowing for *ngFor and *ngIf (#26203)
This commit adds an ngTemplateGuard_ngIf static method to the NgIf
directive and an ngTemplateContextGuard static method to NgFor. The
function of these two static methods is to enable type narrowing
within generated type checking code for consumers of the directives.

PR Close #26203
2018-10-04 10:11:17 -07:00
868047e87f feat(ivy): augment selector scopes to extract additional metadata (#26203)
Before type checking can be turned on in ngtsc, appropriate metadata for
each component and directive must be determined. This commit adds tracking
of the extra metadata in *DefWithMeta types to the selector scope handling,
allowing for later extraction for type-checking purposes.

PR Close #26203
2018-10-04 10:11:17 -07:00
5f1273ba2e feat(ivy): introduce type-checking context API (#26203)
This commit introduces the template type-checking context API, which manages
inlining of type constructors and type-check blocks into ts.SourceFiles.
This API will be used by ngtsc to generate a type-checking ts.Program.

An TypeCheckProgramHost is provided which can wrap a normal ts.CompilerHost
and intercept getSourceFile() calls. This can be used to provide source
files with type check blocks to a ts.Program for type-checking.

PR Close #26203
2018-10-04 10:11:17 -07:00
355a7cae3c feat(ivy): introduce the type check block compiler (#26203)
This commit introduces the main functionality of the type-check compiler:
generation of type check blocks. Type check blocks are blocks of TypeScript
code which can be inlined into source files, and when processed by the
TypeChecker will give information about any typing errors in template
expressions.

PR Close #26203
2018-10-04 10:11:17 -07:00
4c615f7de7 refactor(ivy): move the expr/stmt translator to a separate target (#26203)
Template type-checking will make use of expression and statement
translation as well as the ImportManager, so this code needs to
live in a separate build target which can be depended on by both
the main ngtsc transform as well as the template type-checking
mechanism. This refactor introduces a separate build target
for that code.

PR Close #26203
2018-10-04 10:11:17 -07:00
79466baef8 fix(ivy): remove metadata from *Def and introduce *DefWithMeta types (#26203)
Previously in Ivy, metadata for directives/components/modules/etc was
carried in .d.ts files inside type information encoded on the
DirectiveDef, ComponentDef, NgModuleDef, etc types of Ivy definition
fields. This works well, but has the side effect of complicating Ivy's
runtime code as these extra generic type parameters had to be specified
as <any> throughout the codebase. *DefInternal types were introduced
previously to mitigate this issue, but that's the wrong way to solve
the problem.

This commit returns *Def types to their original form, with no metadata
attached. Instead, new *DefWithMeta types are introduced that alias the
plain definition types and add extra generic parameters. This way the
only code that needs to deal with the extra metadata parameters is the
compiler code that reads and writes them - the existence of this metadata
is transparent to the runtime, as it should be.

PR Close #26203
2018-10-04 10:11:17 -07:00
b0070dfb9a feat(ivy): introduce typecheck package and a type constructor generator (#26203)
This commit introduces //packages/compiler-cli/src/ngtsc/typecheck as a
container for template type-checking code, and implements an initial API:
type constructor generation.

Type constructors are static methods on component/directive types with
no runtime implementation. The methods are used during compilation to
enable inference of a component or directive's generic type parameters
from the types of expressions bound to any of their @Inputs. A type
constructor looks like:

class Directive<T> {
  someInput: T;
  static ngTypeCtor<T>(init: Partial<Pick<Directive<T>, 'someInput'>>): Directive<T>;
}

It can be used to infer a type for T based on the input:

const _dir = Directive.ngTypeCtor({someInput: 'string'}); // Directive<T>

PR Close #26203
2018-10-04 10:11:17 -07:00
9ed4e3df60 feat(ivy): introduce a new compiler API for operating on templates (#26203)
This commit introduces the "t2" API, which processes parsed template ASTs
and performs a number of functions such as binding (the process of
semantically interpreting cross-references within the template) and
directive matching. The API is modeled on TypeScript's TypeChecker API,
with oracle methods that give access to collected metadata.

This work is a prerequisite for the upcoming template type-checking
functionality, and will also become the basis for a refactored
TemplateDefinitionBuilder.

PR Close #26203
2018-10-04 10:11:17 -07:00
a2da485d90 feat(ivy): add generics to the SelectorMatcher API (#26203)
This commit adds a generic type parameter to the SelectorMatcher
class and its associated response types. This makes the API for
matching selectors and obtaining information about the matched
directives significantly more ergonomic and type-safe.

PR Close #26203
2018-10-04 10:11:17 -07:00
9cb17ecc39 refactor(ivy): extract directive matching code into a utility function (#26203)
Upcoming implementation work for template type-checking will need to reuse the
code which matches directives inside a template, so this refactor commit moves
the code to a shared location in preparation.

This commit pulls the code needed to match directives against a template node
out of the TemplateDefinitionBuilder into a utility function, in preparation
for template type-checking and other TemplateDefinitionBuilder refactoring.

PR Close #26203
2018-10-04 10:11:16 -07:00
35936864bc docs: add Suguru Inatomi to GDE resources (#26219)
PR Close #26219
2018-10-04 10:10:52 -07:00
532e53678d refactor(router): get guards only one time and simplify guard operator signature (#26239)
PR Close #26239
2018-10-04 10:10:28 -07:00
f859d83298 refactor(router): move pre activation helpers into utils (#26239)
PR Close #26239
2018-10-04 10:10:28 -07:00
ac68c75e26 refactor(router): convert PreActivation's resolve data to pure functions & remove PreActivation class (#26239)
PR Close #26239
2018-10-04 10:10:28 -07:00
fe45b9cebd refactor(router): convert PreActivation's check guards to pure functions (#26239)
PR Close #26239
2018-10-04 10:10:28 -07:00
aaaa34021c fix(ivy): sanitize tag name while generating listener function name (#26237)
PR Close #26237
2018-10-03 15:29:49 -07:00
730679964f refactor(ivy): flatten LInjector into LViewData (#26220)
PR Close #26220
2018-10-03 15:27:57 -07:00
cb59d87489 feat(ivy): compiler support to generate QUERY_READ_FROM_NODE calls (#26171)
PR Close #26171
2018-10-03 12:28:23 -07:00
d216a46412 release: ts_api_guardian 0.4.0 (#26206)
PR Close #26206
2018-10-02 13:46:41 -07:00
893 changed files with 30654 additions and 24625 deletions

View File

@ -1,2 +1,3 @@
node_modules node_modules
dist dist
aio/node_modules

View File

@ -13,7 +13,7 @@ a GitHub token that enables publishing snapshots.
To create the github_token file, we take this approach: To create the github_token file, we take this approach:
- Find the angular-builds:token in http://valentine - Find the angular-builds:token in http://valentine
- Go inside the ngcontainer docker image so you use the same version of openssl as we will at runtime: `docker run --rm -it angular/ngcontainer` - Go inside the CircleCI default docker image so you use the same version of openssl as we will at runtime: `docker run --rm -it circleci/node:10.12`
- echo "https://[token]:@github.com" > credentials - echo "https://[token]:@github.com" > credentials
- openssl aes-256-cbc -e -in credentials -out .circleci/github_token -k $KEY - openssl aes-256-cbc -e -in credentials -out .circleci/github_token -k $KEY
- If needed, base64-encode the result so you can copy-paste it out of docker: `base64 github_token` - If needed, base64-encode the result so you can copy-paste it out of docker: `base64 github_token`

View File

@ -7,41 +7,53 @@
# To validate changes, use an online parser, eg. # To validate changes, use an online parser, eg.
# http://yaml-online-parser.appspot.com/ # http://yaml-online-parser.appspot.com/
# Variables # Note that the browser docker image comes with Chrome and Firefox preinstalled. This is just
# needed for jobs that run tests without Bazel. Bazel runs tests with browsers that will be
## IMPORTANT # fetched by the Webtesting rules. Therefore for jobs that run tests with Bazel, we don't need a
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of # docker image with browsers pre-installed.
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file. # **NOTE**: If you change the version of the docker images, also change the `cache_key` suffix.
var_1: &docker_image angular/ngcontainer:0.7.0 var_1: &default_docker_image circleci/node:10.12
var_2: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.7.0 var_2: &browsers_docker_image circleci/node:10.12-browsers
var_3: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-node-10.12
# Define common ENV vars # Define common ENV vars
var_3: &define_env_vars var_4: &define_env_vars
run: echo "export PROJECT_ROOT=$(pwd)" >> $BASH_ENV
# See remote cache documentation in /docs/BAZEL.md
var_4: &setup-bazel-remote-cache
run: run:
name: Start up bazel remote cache proxy name: Define environment variables
command: ~/bazel-remote-proxy -backend circleci:// command: ./.circleci/env.sh
background: true
var_5: &setup_bazel_remote_execution var_5: &setup_bazel_remote_execution
run: run:
name: "Setup bazel RBE remote execution" name: "Setup bazel RBE remote execution"
command: openssl aes-256-cbc -d -in .circleci/gcp_token -k "${CIRCLE_PROJECT_REPONAME}" -out /home/circleci/.gcp_credentials && echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/circleci/.gcp_credentials" >> $BASH_ENV && sudo bash -c "cat .circleci/rbe-bazel.rc >> /etc/bazel.bazelrc" command: openssl aes-256-cbc -d -in .circleci/gcp_token -k "$CI_REPO_NAME" -out /home/circleci/.gcp_credentials && echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/circleci/.gcp_credentials" >> $BASH_ENV && sudo bash -c "cat .circleci/rbe-bazel.rc >> /etc/bazel.bazelrc"
# Settings common to each job # Settings common to each job
anchor_1: &job_defaults var_6: &job_defaults
working_directory: ~/ng working_directory: ~/ng
docker: docker:
- image: *docker_image - image: *default_docker_image
var_7: &start-xvfb
run:
name: Running X virtual framebuffer
command: Xvfb :99 -screen 0 1280x1024x24
background: true
# After checkout, rebase on top of master. # After checkout, rebase on top of master.
# Similar to travis behavior, but not quite the same. # Similar to travis behavior, but not quite the same.
# See https://discuss.circleci.com/t/1662 # See https://discuss.circleci.com/t/1662
anchor_2: &post_checkout var_8: &post_checkout
post: git pull --ff-only origin "refs/pull/${CIRCLE_PULL_REQUEST//*pull\//}/merge" post: git pull --ff-only origin "refs/pull/${CI_PULL_REQUEST//*pull\//}/merge"
var_9: &yarn_install
run:
name: Running Yarn install
command: yarn install --frozen-lockfile --non-interactive
var_10: &setup_circleci_bazel_config
run:
name: Setting up CircleCI bazel configuration
command: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
version: 2 version: 2
jobs: jobs:
@ -51,43 +63,38 @@ jobs:
steps: steps:
- checkout: - checkout:
<<: *post_checkout <<: *post_checkout
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc - restore_cache:
key: *cache_key
- *define_env_vars
- *setup_circleci_bazel_config
- *yarn_install
# Check BUILD.bazel formatting before we have a node_modules directory
# Then we don't need any exclude pattern to avoid checking those files
- run: 'yarn buildifier -mode=check || - run: 'yarn buildifier -mode=check ||
(echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)' (echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)'
# Run the skylark linter to check our Bazel rules # Run the skylark linter to check our Bazel rules
- run: 'yarn skylint || - run: 'yarn skylint ||
(echo -e "\n.bzl files have lint errors. Please run ''yarn skylint''"; exit 1)' (echo -e "\n.bzl files have lint errors. Please run ''yarn skylint''"; exit 1)'
- restore_cache:
key: *cache_key
- run: yarn install --frozen-lockfile --non-interactive
- run: ./node_modules/.bin/gulp lint - run: ./node_modules/.bin/gulp lint
test: test:
<<: *job_defaults <<: *job_defaults
resource_class: xlarge resource_class: xlarge
steps: steps:
- *define_env_vars
- checkout: - checkout:
<<: *post_checkout <<: *post_checkout
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc - restore_cache:
key: *cache_key
- *define_env_vars
- *setup_circleci_bazel_config
- *yarn_install
- run: bazel info release
- run: bazel run @nodejs//:yarn
# Use bazel query so that we explicitly ask for all buildable targets to be built as well
# This avoids waiting for the slowest build target to finish before running the first test
# See https://github.com/bazelbuild/bazel/issues/4257
# NOTE: Angular developers should typically just bazel build //packages/... or bazel test //packages/...
# Setup remote execution and run RBE-compatible tests. # Setup remote execution and run RBE-compatible tests.
- *setup_bazel_remote_execution - *setup_bazel_remote_execution
- run: bazel query --output=label //... | xargs bazel test --build_tag_filters=-ivy-only --test_tag_filters=-manual,-ivy-only,-local - run: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only,-local
# Now run RBE incompatible tests locally. # Now run RBE incompatible tests locally.
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc - run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
- run: bazel query --output=label //... | xargs bazel test --build_tag_filters=-ivy-only,local --test_tag_filters=-manual,-ivy-only,local - run: yarn bazel test //... --build_tag_filters=-ivy-only,local --test_tag_filters=-ivy-only,local
# CircleCI will allow us to go back and view/download these artifacts from past builds. # CircleCI will allow us to go back and view/download these artifacts from past builds.
# Also we can use a service like https://buildsize.org/ to automatically track binary size of these artifacts. # Also we can use a service like https://buildsize.org/ to automatically track binary size of these artifacts.
@ -119,29 +126,165 @@ jobs:
<<: *job_defaults <<: *job_defaults
resource_class: xlarge resource_class: xlarge
steps: steps:
- *define_env_vars # don't run this job on the patch branch (to preserve resources)
- run: circleci step halt
- checkout: - checkout:
<<: *post_checkout <<: *post_checkout
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc - restore_cache:
key: *cache_key
- run: bazel run @yarn//:yarn - *define_env_vars
- *setup_circleci_bazel_config
- *yarn_install
- *setup_bazel_remote_execution - *setup_bazel_remote_execution
- run: bazel query --output=label //... | xargs bazel test --define=compile=jit --build_tag_filters=ivy-jit --test_tag_filters=-manual,ivy-jit
- run: yarn test-ivy-jit //...
test_ivy_aot: test_ivy_aot:
<<: *job_defaults <<: *job_defaults
resource_class: xlarge resource_class: xlarge
steps: steps:
- *define_env_vars # don't run this job on the patch branch (to preserve resources)
- run: circleci step halt
- checkout: - checkout:
<<: *post_checkout <<: *post_checkout
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc - restore_cache:
key: *cache_key
- run: bazel run @yarn//:yarn - *define_env_vars
- *setup_circleci_bazel_config
- *yarn_install
- *setup_bazel_remote_execution - *setup_bazel_remote_execution
- run: bazel query --output=label //... | xargs bazel test --define=compile=local --build_tag_filters=ivy-local --test_tag_filters=-manual,ivy-local
# This job should only be run on PR builds, where `CIRCLE_PR_NUMBER` is defined. - run: yarn test-ivy-aot //...
test_aio:
<<: *job_defaults
docker:
# Needed because the AIO tests and the PWA score test depend on Chrome being available.
- image: *browsers_docker_image
steps:
- checkout:
<<: *post_checkout
- restore_cache:
key: *cache_key
- *define_env_vars
- *start-xvfb
# Build aio
- run: yarn --cwd aio build --progress=false
# Lint the code
- run: yarn --cwd aio lint
# Run PWA-score tests
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
# Check the bundle sizes.
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
- run: yarn --cwd aio payload-size
# Run unit tests
- run: yarn --cwd aio test --watch=false
# Run e2e tests
- run: yarn --cwd aio e2e
# Run unit tests for Firebase redirects
- run: yarn --cwd aio redirects-test
deploy_aio:
<<: *job_defaults
docker:
# Needed because before deploying the deploy-production script runs the PWA score tests.
- image: *browsers_docker_image
steps:
- checkout:
<<: *post_checkout
- restore_cache:
key: *cache_key
- *define_env_vars
- *start-xvfb
# Deploy angular.io to production (if necessary)
- run: setPublicVar CI_STABLE_BRANCH "$(npm info @angular/core dist-tags.latest | sed -r 's/^\s*([0-9]+\.[0-9]+)\.[0-9]+.*$/\1.x/')"
- run: yarn --cwd aio deploy-production
test_aio_local:
<<: *job_defaults
docker:
# Needed because the AIO tests and the PWA score test depend on Chrome being available.
- image: *browsers_docker_image
steps:
- checkout:
<<: *post_checkout
- restore_cache:
key: *cache_key
- attach_workspace:
at: dist
- *define_env_vars
- *start-xvfb
# Build aio (with local Angular packages)
- run: yarn --cwd aio build-local --progress=false
# Run PWA-score tests
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
# Run unit tests
- run: yarn --cwd aio test --watch=false
# Run e2e tests
- run: yarn --cwd aio e2e
test_aio_tools:
<<: *job_defaults
steps:
- checkout:
<<: *post_checkout
- restore_cache:
key: *cache_key
- attach_workspace:
at: dist
- *define_env_vars
# Install
- run: yarn --cwd aio install --frozen-lockfile --non-interactive
- run: yarn --cwd aio extract-cli-command-docs
# Run tools tests
- run: yarn --cwd aio tools-test
- run: ./aio/aio-builds-setup/scripts/test.sh
test_docs_examples_0:
<<: *job_defaults
docker:
# Needed because the example e2e tests depend on Chrome.
- image: *browsers_docker_image
steps:
- checkout:
<<: *post_checkout
- restore_cache:
key: *cache_key
- attach_workspace:
at: dist
- *define_env_vars
- *start-xvfb
# Install root
- *yarn_install
# Install aio
- run: yarn --cwd aio install --frozen-lockfile --non-interactive
# Run examples tests
- run: yarn --cwd aio example-e2e --setup --local --shard=0/2
test_docs_examples_1:
<<: *job_defaults
docker:
# Needed because the example e2e tests depend on Chrome.
- image: *browsers_docker_image
steps:
- checkout:
<<: *post_checkout
- restore_cache:
key: *cache_key
- attach_workspace:
at: dist
- *define_env_vars
- *start-xvfb
# Install root
- *yarn_install
# Install aio
- run: yarn --cwd aio install --frozen-lockfile --non-interactive
# Run examples tests
- run: yarn --cwd aio example-e2e --setup --local --shard=1/2
# This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`.
aio_preview: aio_preview:
<<: *job_defaults <<: *job_defaults
environment: environment:
@ -151,28 +294,32 @@ jobs:
<<: *post_checkout <<: *post_checkout
- restore_cache: - restore_cache:
key: *cache_key key: *cache_key
- run: yarn install --frozen-lockfile --non-interactive - *define_env_vars
- run: ./aio/scripts/build-artifacts.sh $AIO_SNAPSHOT_ARTIFACT_PATH $CIRCLE_PR_NUMBER $CIRCLE_SHA1 - *yarn_install
- run: ./aio/scripts/build-artifacts.sh $AIO_SNAPSHOT_ARTIFACT_PATH $CI_PULL_REQUEST $CI_COMMIT
- store_artifacts: - store_artifacts:
path: *aio_preview_artifact_path path: *aio_preview_artifact_path
# The `destination` needs to be kept in synch with the value of # The `destination` needs to be kept in synch with the value of
# `AIO_ARTIFACT_PATH` in `aio/aio-builds-setup/Dockerfile` # `AIO_ARTIFACT_PATH` in `aio/aio-builds-setup/Dockerfile`
destination: aio/dist/aio-snapshot.tgz destination: aio/dist/aio-snapshot.tgz
# This job should only be run on PR builds, where `CIRCLE_PR_NUMBER` is defined. # This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`.
test_aio_preview: test_aio_preview:
<<: *job_defaults <<: *job_defaults
docker:
# Needed because the test-preview script runs e2e tests and the PWA score test with Chrome.
- image: *browsers_docker_image
steps: steps:
- checkout: - checkout:
<<: *post_checkout <<: *post_checkout
- restore_cache: - restore_cache:
key: *cache_key key: *cache_key
- *define_env_vars
- *start-xvfb
- run: yarn install --cwd aio --frozen-lockfile --non-interactive - run: yarn install --cwd aio --frozen-lockfile --non-interactive
- run: - run:
name: Wait for preview and run tests name: Wait for preview and run tests
command: | command: node aio/scripts/test-preview.js $CI_PULL_REQUEST $CI_COMMIT $CI_AIO_MIN_PWA_SCORE
source "./scripts/ci/env.sh" print
xvfb-run --auto-servernum node aio/scripts/test-preview.js $CIRCLE_PR_NUMBER $CIRCLE_SHA1 $AIO_MIN_PWA_SCORE
# This job exists only for backwards-compatibility with old scripts and tests # This job exists only for backwards-compatibility with old scripts and tests
# that rely on the pre-Bazel dist/packages-dist layout. # that rely on the pre-Bazel dist/packages-dist layout.
@ -185,12 +332,15 @@ jobs:
<<: *job_defaults <<: *job_defaults
resource_class: xlarge resource_class: xlarge
steps: steps:
- *define_env_vars
- checkout: - checkout:
<<: *post_checkout <<: *post_checkout
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc - restore_cache:
- run: bazel run @nodejs//:yarn key: *cache_key
- *define_env_vars
- *setup_circleci_bazel_config
- *yarn_install
- *setup_bazel_remote_execution - *setup_bazel_remote_execution
- run: scripts/build-packages-dist.sh - run: scripts/build-packages-dist.sh
# Save the npm packages from //packages/... for other workflow jobs to read # Save the npm packages from //packages/... for other workflow jobs to read
@ -200,7 +350,7 @@ jobs:
paths: paths:
- packages-dist - packages-dist
- packages-dist-ivy-jit - packages-dist-ivy-jit
- packages-dist-ivy-local - packages-dist-ivy-aot
# We run the integration tests outside of Bazel for now. # We run the integration tests outside of Bazel for now.
# They are a separate workflow job so that they can be easily re-run. # They are a separate workflow job so that they can be easily re-run.
@ -210,35 +360,42 @@ jobs:
# See comments inside the integration/run_tests.sh script. # See comments inside the integration/run_tests.sh script.
integration_test: integration_test:
<<: *job_defaults <<: *job_defaults
docker:
# Needed because the integration tests expect Chrome to be installed (e.g cli-hello-world)
- image: *browsers_docker_image
# Note: we run Bazel in one of the integration tests, and it can consume >2G # Note: we run Bazel in one of the integration tests, and it can consume >2G
# of memory. Together with the system under test, this can exhaust the RAM # of memory. Together with the system under test, this can exhaust the RAM
# on a 4G worker so we use a larger machine here too. # on a 4G worker so we use a larger machine here too.
resource_class: xlarge resource_class: xlarge
steps: steps:
- *define_env_vars
- checkout: - checkout:
<<: *post_checkout <<: *post_checkout
- restore_cache:
key: *cache_key
- attach_workspace: - attach_workspace:
at: dist at: dist
- run: xvfb-run --auto-servernum ./integration/run_tests.sh - *define_env_vars
- *start-xvfb
- run: ./integration/run_tests.sh
# This job updates the content of repos like github.com/angular/core-builds # This job updates the content of repos like github.com/angular/core-builds
# for every green build on angular/angular. # for every green build on angular/angular.
publish_snapshot: publish_snapshot:
<<: *job_defaults <<: *job_defaults
steps: steps:
- checkout:
<<: *post_checkout
- *define_env_vars
# See below - ideally this job should not trigger for non-upstream builds. # See below - ideally this job should not trigger for non-upstream builds.
# But since it does, we have to check this condition. # But since it does, we have to check this condition.
- run: - run:
name: Skip this job for Pull Requests and Fork builds name: Skip this job for Pull Requests and Fork builds
# Note, `|| true` on the end makes this step always exit 0 # Note, `|| true` on the end makes this step always exit 0
command: '[[ command: '[[
-v CIRCLE_PR_NUMBER "$CI_PULL_REQUEST" != "false"
|| "$CIRCLE_PROJECT_USERNAME" != "angular" || "$CI_REPO_OWNER" != "angular"
|| "$CIRCLE_PROJECT_REPONAME" != "angular" || "$CI_REPO_NAME" != "angular"
]] && circleci step halt || true' ]] && circleci step halt || true'
- checkout:
<<: *post_checkout
- attach_workspace: - attach_workspace:
at: dist at: dist
# CircleCI has a config setting to force SSH for all github connections # CircleCI has a config setting to force SSH for all github connections
@ -252,12 +409,24 @@ jobs:
aio_monitoring: aio_monitoring:
<<: *job_defaults <<: *job_defaults
docker:
# This job needs Chrome to be globally installed because the tests run with Protractor
# which does not load the browser through the Bazel webtesting rules.
- image: *browsers_docker_image
steps: steps:
- checkout: - checkout:
<<: *post_checkout <<: *post_checkout
- restore_cache: - restore_cache:
key: *cache_key key: *cache_key
- run: xvfb-run --auto-servernum ./aio/scripts/test-production.sh - *define_env_vars
- *start-xvfb
- run:
name: Run tests against the deployed apps
command: ./aio/scripts/test-production.sh $CI_AIO_MIN_PWA_SCORE
- run:
name: Notify caretaker about failure
command: 'curl --request POST --header "Content-Type: application/json" --data "{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" $CI_SECRET_SLACK_CARETAKER_WEBHOOK_URL'
when: on_fail
workflows: workflows:
version: 2 version: 2
@ -268,6 +437,22 @@ workflows:
- test_ivy_jit - test_ivy_jit
- test_ivy_aot - test_ivy_aot
- build-packages-dist - build-packages-dist
- test_aio
- deploy_aio:
requires:
- test_aio
- test_aio_local:
requires:
- build-packages-dist
- test_aio_tools:
requires:
- build-packages-dist
- test_docs_examples_0:
requires:
- build-packages-dist
- test_docs_examples_1:
requires:
- build-packages-dist
- aio_preview: - aio_preview:
# Only run on PR builds. (There can be no previews for non-PR builds.) # Only run on PR builds. (There can be no previews for non-PR builds.)
filters: filters:
@ -290,6 +475,10 @@ workflows:
- test_ivy_jit - test_ivy_jit
- test_ivy_aot - test_ivy_aot
- integration_test - integration_test
# Only publish if `aio`/`docs` tests using the locally built Angular packages pass
- test_aio_local
- test_docs_examples_0
- test_docs_examples_1
# Get the artifacts to publish from the build-packages-dist job # Get the artifacts to publish from the build-packages-dist job
# since the publishing script expects the legacy outputs layout. # since the publishing script expects the legacy outputs layout.
- build-packages-dist - build-packages-dist

View File

@ -0,0 +1,38 @@
####################################################################################################
# Helpers for defining environment variables for CircleCI.
#
# In CircleCI, each step runs in a new shell. The way to share ENV variables across steps is to
# export them from `$BASH_ENV`, which is automatically sourced at the beginning of every step (for
# the default `bash` shell).
#
# See also https://circleci.com/docs/2.0/env-vars/#using-bash_env-to-set-environment-variables.
####################################################################################################
# Set and print an environment variable.
#
# Use this function for setting environment variables that are public, i.e. it is OK for them to be
# visible to anyone through the CI logs.
#
# Usage: `setPublicVar <name> <value>`
function setPublicVar() {
setSecretVar $1 $2;
echo "$1=$2";
}
# Set (without printing) an environment variable.
#
# Use this function for setting environment variables that are secret, i.e. should not be visible to
# everyone through the CI logs.
#
# Usage: `setSecretVar <name> <value>`
function setSecretVar() {
# WARNING: Secrets (e.g. passwords, access tokens) should NOT be printed.
# (Keep original shell options to restore at the end.)
local -r originalShellOptions=$(set +o);
set +x -eu -o pipefail;
echo "export $1=\"${2:-}\";" >> $BASH_ENV;
# Restore original shell options.
eval "$originalShellOptions";
}

35
.circleci/env.sh Executable file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Load helpers and make them available everywhere (through `$BASH_ENV`).
readonly envHelpersPath="`dirname $0`/env-helpers.inc.sh";
source $envHelpersPath;
echo "source $envHelpersPath;" >> $BASH_ENV;
####################################################################################################
# Define PUBLIC environment variables for CircleCI.
####################################################################################################
setPublicVar PROJECT_ROOT "$(pwd)";
setPublicVar CI_AIO_MIN_PWA_SCORE "95";
# This is the branch being built; e.g. `pull/12345` for PR builds.
setPublicVar CI_BRANCH "$CIRCLE_BRANCH";
setPublicVar CI_COMMIT "$CIRCLE_SHA1";
# `CI_COMMIT_RANGE` will only be available when `CIRCLE_COMPARE_URL` is also available,
# i.e. on push builds (a.k.a. non-PR builds). That is fine, since we only need it in push builds.
setPublicVar CI_COMMIT_RANGE "$(sed -r 's|^.*/([0-9a-f]+\.\.\.[0-9a-f]+)$|\1|i' <<< ${CIRCLE_COMPARE_URL:-})";
setPublicVar CI_PULL_REQUEST "${CIRCLE_PR_NUMBER:-false}";
setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME";
setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME";
####################################################################################################
# Define SECRET environment variables for CircleCI.
####################################################################################################
setSecretVar CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN "$AIO_DEPLOY_TOKEN";
setSecretVar CI_SECRET_PAYLOAD_FIREBASE_TOKEN "$ANGULAR_PAYLOAD_TOKEN";
# Defined in https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
setSecretVar CI_SECRET_SLACK_CARETAKER_WEBHOOK_URL "$SLACK_CARETAKER_WEBHOOK_URL";
# Source `$BASH_ENV` to make the variables available immediately.
source $BASH_ENV;

Binary file not shown.

View File

@ -10,17 +10,17 @@ Please check if your PR fulfills the following requirements:
What kind of change does this PR introduce? What kind of change does this PR introduce?
<!-- Please check the one that applies to this PR using "x". --> <!-- Please check the one that applies to this PR using "x". -->
```
[ ] Bugfix - [ ] Bugfix
[ ] Feature - [ ] Feature
[ ] Code style update (formatting, local variables) - [ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes) - [ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes - [ ] Build related changes
[ ] CI related changes - [ ] CI related changes
[ ] Documentation content changes - [ ] Documentation content changes
[ ] angular.io application / infrastructure changes - [ ] angular.io application / infrastructure changes
[ ] Other... Please describe: - [ ] Other... Please describe:
```
## What is the current behavior? ## What is the current behavior?
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. --> <!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->
@ -32,10 +32,10 @@ Issue Number: N/A
## Does this PR introduce a breaking change? ## Does this PR introduce a breaking change?
```
[ ] Yes - [ ] Yes
[ ] No - [ ] No
```
<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. --> <!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->

View File

@ -39,6 +39,7 @@ merge:
- "packages/**" - "packages/**"
# list of patterns to ignore for the files changed by the PR # list of patterns to ignore for the files changed by the PR
exclude: exclude:
- "packages/bazel/*.bzl"
- "packages/language-service/**" - "packages/language-service/**"
- "**/.gitignore" - "**/.gitignore"
- "**/.gitkeep" - "**/.gitkeep"
@ -124,3 +125,23 @@ triage:
- -
- "type: RFC / Discussion / question" - "type: RFC / Discussion / question"
- "comp: *" - "comp: *"
# options for the triage PR plugin
triagePR:
# set to true to disable
disabled: false
# number of the milestone to apply when the PR has not been triaged yet
needsTriageMilestone: 83,
# number of the milestone to apply when the PR is triaged
defaultMilestone: 82,
# arrays of labels that determine if a PR has been triaged by the caretaker
l1TriageLabels:
-
- "comp: *"
# arrays of labels that determine if a PR has been fully triaged
l2TriageLabels:
-
- "type: *"
- "effort*"
- "risk*"
- "comp: *"

View File

@ -276,6 +276,9 @@ groups:
- "aio/content/guide/forms.md" - "aio/content/guide/forms.md"
- "aio/content/examples/forms/*" - "aio/content/examples/forms/*"
- "aio/content/images/guide/forms/*" - "aio/content/images/guide/forms/*"
- "aio/content/guide/forms-overview.md"
- "aio/content/examples/forms-overview/*"
- "aio/content/images/guide/forms-overview/*"
- "aio/content/guide/form-validation.md" - "aio/content/guide/form-validation.md"
- "aio/content/examples/form-validation/*" - "aio/content/examples/form-validation/*"
- "aio/content/images/guide/form-validation/*" - "aio/content/images/guide/form-validation/*"

View File

@ -30,14 +30,6 @@ env:
# GITHUB_TOKEN_ANGULAR=<github token, a personal access token of the angular-builds account, account access in valentine> # GITHUB_TOKEN_ANGULAR=<github token, a personal access token of the angular-builds account, account access in valentine>
# This is needed for the e2e Travis matrix task to publish packages to github for continuous packages delivery. # This is needed for the e2e Travis matrix task to publish packages to github for continuous packages delivery.
- secure: "aCdHveZuY8AT4Jr1JoJB4LxZsnGWRe/KseZh1YXYe5UtufFCtTVHvUcLn0j2aLBF0KpdyS+hWf0i4np9jthKu2xPKriefoPgCMpisYeC0MFkwbmv+XlgkUbgkgVZMGiVyX7DCYXVahxIoOUjVMEDCbNiHTIrfEuyq24U3ok2tHc=" - secure: "aCdHveZuY8AT4Jr1JoJB4LxZsnGWRe/KseZh1YXYe5UtufFCtTVHvUcLn0j2aLBF0KpdyS+hWf0i4np9jthKu2xPKriefoPgCMpisYeC0MFkwbmv+XlgkUbgkgVZMGiVyX7DCYXVahxIoOUjVMEDCbNiHTIrfEuyq24U3ok2tHc="
# FIREBASE_TOKEN
# This is needed for publishing builds to the "aio-staging" and "angular-io" firebase projects.
# This token was generated using the aio-deploy@angular.io account using `firebase login:ci` and password from valentine
- secure: "L5CyQmpwWtoR4Qi4xlWQh/cL1M6ZeJL4W4QAr4HdKFMgYt9h+Whqkymyh2NxwmCbPvWa7yUd+OiLQUDCY7L2VIg16hTwoe2CgYDyQA0BEwLzxtRrJXl93TfwMlrUx5JSIzAccD6D4sjtz8kSFMomK2Nls33xOXOukwyhVMjd0Cg="
# ANGULAR_PAYLOAD_FIREBASE_TOKEN
# This is for payload size data to "angular-payload-size" firebase project
# This token was generated using the payload@angular.io account using `firebase login:ci` and password from valentine
- secure: "SxotP/ymNy6uWAVbfwM9BlwETPEBpkRvU/F7fCtQDDic99WfQHzzUSQqHTk8eKk3GrGAOSL09vT0WfStQYEIGEoS5UHWNgOnelxhw+d5EnaoB8vQ0dKQBTK092hQg4feFprr+B/tCasyMV6mVwpUzZMbIJNn/Rx7H5g1bp+Gkfg="
matrix: matrix:
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete. # Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
- CI_MODE=e2e - CI_MODE=e2e
@ -47,10 +39,6 @@ env:
# - CI_MODE=browserstack_required # - CI_MODE=browserstack_required
- CI_MODE=saucelabs_optional - CI_MODE=saucelabs_optional
- CI_MODE=browserstack_optional - CI_MODE=browserstack_optional
- CI_MODE=aio_tools_test
- CI_MODE=aio
- CI_MODE=aio_e2e AIO_SHARD=0
- CI_MODE=aio_e2e AIO_SHARD=1
matrix: matrix:
fast_finish: true fast_finish: true
@ -68,8 +56,6 @@ install:
script: script:
- ./scripts/ci/build.sh - ./scripts/ci/build.sh
- ./scripts/ci/test.sh - ./scripts/ci/test.sh
# deploy is part of 'script' and not 'after_success' so that we fail the build if the deployment fails
- ./scripts/ci/deploy.sh
- ./scripts/ci/angular.sh - ./scripts/ci/angular.sh
# all the scripts under this line will not quickly abort in case ${TRAVIS_TEST_RESULT} is 1 (job failure) # all the scripts under this line will not quickly abort in case ${TRAVIS_TEST_RESULT} is 1 (job failure)
- ./scripts/ci/cleanup.sh - ./scripts/ci/cleanup.sh

View File

@ -8,13 +8,6 @@ exports_files([
"protractor-perf.conf.js", "protractor-perf.conf.js",
]) ])
# Developers should always run `bazel run :install`
# This ensures that package.json in subdirectories get installed as well.
alias(
name = "install",
actual = "@nodejs//:yarn",
)
filegroup( filegroup(
name = "web_test_bootstrap_scripts", name = "web_test_bootstrap_scripts",
# do not sort # do not sort
@ -50,6 +43,7 @@ load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
# set which is required to support the call to `global.gc()`. # set which is required to support the call to `global.gc()`.
nodejs_binary( nodejs_binary(
name = "@angular/bazel/ngc-wrapped", name = "@angular/bazel/ngc-wrapped",
configuration_env_vars = ["compile"],
data = ["@npm//@angular/bazel"], data = ["@npm//@angular/bazel"],
entry_point = "@angular/bazel/src/ngc-wrapped/index.js", entry_point = "@angular/bazel/src/ngc-wrapped/index.js",
install_source_map_support = False, install_source_map_support = False,

View File

@ -1,27 +1,97 @@
<a name="7.0.0-rc.0"></a> <a name="7.0.2"></a>
# [7.0.0-rc.0](https://github.com/angular/angular/compare/7.0.0-beta.7...7.0.0-rc.0) (2018-09-28) ## [7.0.2](https://github.com/angular/angular/compare/7.0.1...7.0.2) (2018-10-31)
### Features
* add support for TypeScript 3.1 ([#26151](https://github.com/angular/angular/issues/26151)) ([9993c72](https://github.com/angular/angular/commit/9993c72))
<a name="7.0.0-beta.7"></a>
# [7.0.0-beta.7](https://github.com/angular/angular/compare/7.0.0-beta.6...7.0.0-beta.7) (2018-09-26)
### Bug Fixes ### Bug Fixes
* **core:** add missing `peerDependency ` to `[@angular](https://github.com/angular)/compiler` ([#26033](https://github.com/angular/angular/issues/26033)) ([549de1e](https://github.com/angular/angular/commit/549de1e)), closes [/github.com/angular/angular/commit/919f42fea1df4b9e38b7d688aef5f2de668e9d3e#diff-58563046c4439699f2e6a89187099a54](https://github.com//github.com/angular/angular/commit/919f42fea1df4b9e38b7d688aef5f2de668e9d3e/issues/diff-58563046c4439699f2e6a89187099a54) * **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([c01f340](https://github.com/angular/angular/commit/c01f340))
* **service-worker:** do not blow up when caches are unwritable ([#26042](https://github.com/angular/angular/issues/26042)) ([2bd767c](https://github.com/angular/angular/commit/2bd767c)) * **core:** Remove static dependency from [@angular](https://github.com/angular)/core to [@angular](https://github.com/angular)/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([#26879](https://github.com/angular/angular/issues/26879)) ([257ac83](https://github.com/angular/angular/commit/257ac83))
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([b3c6409](https://github.com/angular/angular/commit/b3c6409))
<a name="7.0.1"></a>
## [7.0.1](https://github.com/angular/angular/compare/7.0.0...7.0.1) (2018-10-24)
<a name="7.0.0"></a>
# [7.0.0](https://github.com/angular/angular/compare/7.0.0-rc.1...7.0.0) (2018-10-18)
### Release Highlights & Update instructions
To learn about the release highlights and our new CLI-powered update workflow for your projects please check out the [v7 release announcement](https://blog.angular.io/version-7-of-angular-cli-prompts-virtual-scroll-drag-and-drop-and-more-c594e22e7b8c).
### Dependency updates
* @angular/core now depends on
* TypeScript 3.1
* RxJS 6.3
* @angular/platform-server now depends on Domino 2.1
### Features ### Features
* **core:** add DoBootstrap interface. ([#24558](https://github.com/angular/angular/issues/24558)) ([732026c](https://github.com/angular/angular/commit/732026c)), closes [#24557](https://github.com/angular/angular/issues/24557)
* **compiler:** add "original" placeholder value on extracted XMB ([#25079](https://github.com/angular/angular/issues/25079)) ([e99d860](https://github.com/angular/angular/commit/e99d860))
* **compiler-cli:** add support to extend `angularCompilerOptions` ([#22717](https://github.com/angular/angular/issues/22717)) ([d7e5bbf](https://github.com/angular/angular/commit/d7e5bbf)), closes [#22684](https://github.com/angular/angular/issues/22684) * **compiler-cli:** add support to extend `angularCompilerOptions` ([#22717](https://github.com/angular/angular/issues/22717)) ([d7e5bbf](https://github.com/angular/angular/commit/d7e5bbf)), closes [#22684](https://github.com/angular/angular/issues/22684)
* **bazel:** add additional parameters to `ts_api_guardian_test` def ([#25694](https://github.com/angular/angular/issues/25694)) ([2a21ca0](https://github.com/angular/angular/commit/2a21ca0))
* **elements:** enable Shadow DOM v1 and slots ([#24861](https://github.com/angular/angular/issues/24861)) ([c9844a2](https://github.com/angular/angular/commit/c9844a2))
* **platform-server:** update domino to v2.1.0 ([#25564](https://github.com/angular/angular/issues/25564)) ([3fb0da2](https://github.com/angular/angular/commit/3fb0da2)) * **platform-server:** update domino to v2.1.0 ([#25564](https://github.com/angular/angular/issues/25564)) ([3fb0da2](https://github.com/angular/angular/commit/3fb0da2))
* **router:** warn if navigation triggered outside Angular zone ([#24959](https://github.com/angular/angular/issues/24959)) ([010e35d](https://github.com/angular/angular/commit/010e35d)), closes [#15770](https://github.com/angular/angular/issues/15770) [#15946](https://github.com/angular/angular/issues/15946) [#24728](https://github.com/angular/angular/issues/24728)
* **router:** add UrlSegment[] to CanLoad interface ([#13127](https://github.com/angular/angular/issues/13127)) ([07d8d39](https://github.com/angular/angular/commit/07d8d39)), closes [#12411](https://github.com/angular/angular/issues/12411)
### Bug Fixes
* add mappings for ngfactory & ngsummary files to their module names in aot summary resolver ([#25335](https://github.com/angular/angular/issues/25335)) ([02e201a](https://github.com/angular/angular/commit/02e201a))
* **bazel:** Cache fileNameToModuleName lookups ([#25731](https://github.com/angular/angular/issues/25731)) ([f394ba0](https://github.com/angular/angular/commit/f394ba0))
* **bazel:** allow compile_strategy to be (privately) imported ([#25080](https://github.com/angular/angular/issues/25080)) ([0d1d589](https://github.com/angular/angular/commit/0d1d589))
* **bazel:** correct type concatenated to devmode_js ([#25467](https://github.com/angular/angular/issues/25467)) ([fb2c524](https://github.com/angular/angular/commit/fb2c524))
* **bazel:** move bazel managed runtime deps for downstream usage ([#25690](https://github.com/angular/angular/issues/25690)) ([6ed7993](https://github.com/angular/angular/commit/6ed7993))
* **bazel:** only lookup amd module-name tags in .d.ts files ([#25710](https://github.com/angular/angular/issues/25710)) ([42072c4](https://github.com/angular/angular/commit/42072c4))
* **bazel:** protractor rule should include *.e2e-spec.js ([#25701](https://github.com/angular/angular/issues/25701)) ([3809e0f](https://github.com/angular/angular/commit/3809e0f))
* **bazel:** specify the package and lock files using the workspace ([#25694](https://github.com/angular/angular/issues/25694)) ([ddc1335](https://github.com/angular/angular/commit/ddc1335))
* **benchpress:** Use performance.mark() instead of console.time() ([#24114](https://github.com/angular/angular/issues/24114)) ([06d0400](https://github.com/angular/angular/commit/06d0400))
* **common:** register locale data for all equivalent closure locales ([#25867](https://github.com/angular/angular/issues/25867)) ([d83f9d4](https://github.com/angular/angular/commit/d83f9d4))
* **compiler-cli:** correct realPath to realpath. ([#25023](https://github.com/angular/angular/issues/25023)) ([01e6dab](https://github.com/angular/angular/commit/01e6dab))
* **compiler-cli:** use the oldProgram option in watch mode ([#21364](https://github.com/angular/angular/issues/21364)) ([c6e5b97](https://github.com/angular/angular/commit/c6e5b97)), closes [#21361](https://github.com/angular/angular/issues/21361)
* **compiler:** Fix look up of entryComponents in AOT Summaries ([#24892](https://github.com/angular/angular/issues/24892)) ([00d3666](https://github.com/angular/angular/commit/00d3666))
* **compiler:** add hostVars and support pure functions in host bindings ([#25626](https://github.com/angular/angular/issues/25626)) ([b424b31](https://github.com/angular/angular/commit/b424b31))
* **compiler:** update compiler to flatten nested template fns ([#24943](https://github.com/angular/angular/issues/24943)) ([fe14f18](https://github.com/angular/angular/commit/fe14f18))
* **compiler:** update compiler to generate new slot allocations ([#25607](https://github.com/angular/angular/issues/25607)) ([27e2039](https://github.com/angular/angular/commit/27e2039))
* **core:** In Testability.whenStable update callback, pass more complete ([#25010](https://github.com/angular/angular/issues/25010)) ([16c03c0](https://github.com/angular/angular/commit/16c03c0))
* **core:** add missing `peerDependency ` to `[@angular](https://github.com/angular)/compiler` ([#26033](https://github.com/angular/angular/issues/26033)) ([549de1e](https://github.com/angular/angular/commit/549de1e)), closes [/github.com/angular/angular/commit/919f42fea1df4b9e38b7d688aef5f2de668e9d3e#diff-58563046c4439699f2e6a89187099a54](https://github.com//github.com/angular/angular/commit/919f42fea1df4b9e38b7d688aef5f2de668e9d3e/issues/diff-58563046c4439699f2e6a89187099a54)
* **core:** allow null value for renderer setElement(…) ([#17065](https://github.com/angular/angular/issues/17065)) ([ff15043](https://github.com/angular/angular/commit/ff15043)), closes [#13686](https://github.com/angular/angular/issues/13686)
* **core:** do not clear element content when using shadow dom ([#24861](https://github.com/angular/angular/issues/24861)) ([6e828bb](https://github.com/angular/angular/commit/6e828bb))
* **core:** size regression with closure compiler ([#25531](https://github.com/angular/angular/issues/25531)) ([1f59f2f](https://github.com/angular/angular/commit/1f59f2f))
* **core:** throw error message when @Output not initialized ([#19116](https://github.com/angular/angular/issues/19116)) ([adf510f](https://github.com/angular/angular/commit/adf510f)), closes [#3664](https://github.com/angular/angular/issues/3664)
* **elements:** add compiler dependency ([#24861](https://github.com/angular/angular/issues/24861)) ([6143da6](https://github.com/angular/angular/commit/6143da6))
* **elements:** add compiler to integration ([#24861](https://github.com/angular/angular/issues/24861)) ([a080ffc](https://github.com/angular/angular/commit/a080ffc))
* **elements:** strict null checks ([#24861](https://github.com/angular/angular/issues/24861)) ([a8210d0](https://github.com/angular/angular/commit/a8210d0))
* **router:** fix regression where navigateByUrl promise didn't resolve on CanLoad failure ([#26455](https://github.com/angular/angular/issues/26455)) ([1c9b065](https://github.com/angular/angular/commit/1c9b065)), closes [#26284](https://github.com/angular/angular/issues/26284)
* **router:** mount correct component if router outlet was not instantiated and if using a route reuse strategy ([#25313](https://github.com/angular/angular/issues/25313)) ([#25314](https://github.com/angular/angular/issues/25314)) ([8dc2b11](https://github.com/angular/angular/commit/8dc2b11))
* **router:** take base uri into account in `setUpLocationSync()` ([#20244](https://github.com/angular/angular/issues/20244)) ([ba1e25f](https://github.com/angular/angular/commit/ba1e25f)), closes [#20061](https://github.com/angular/angular/issues/20061)
* **service-worker:** clean up caches from old SW versions ([#26319](https://github.com/angular/angular/issues/26319)) ([00b5c7b](https://github.com/angular/angular/commit/00b5c7b))
* **service-worker:** do not blow up when caches are unwritable ([#26042](https://github.com/angular/angular/issues/26042)) ([2bd767c](https://github.com/angular/angular/commit/2bd767c))
* **upgrade:** properly destroy upgraded component elements and descendants ([#26209](https://github.com/angular/angular/issues/26209)) ([071934e](https://github.com/angular/angular/commit/071934e)), closes [#26208](https://github.com/angular/angular/issues/26208)
* **upgrade:** trigger `$destroy` event on upgraded component element ([#25357](https://github.com/angular/angular/issues/25357)) ([2a672a9](https://github.com/angular/angular/commit/2a672a9)), closes [#25334](https://github.com/angular/angular/issues/25334)
<a name="6.1.10"></a>
## [6.1.10](https://github.com/angular/angular/compare/6.1.9...6.1.10) (2018-10-10)
### Bug Fixes
* **platform-browser:** fix [#22155](https://github.com/angular/angular/issues/22155), destroy hammer manager when `HammerInstance.off()` is run ([#22156](https://github.com/angular/angular/issues/22156)) ([3b4d9dc](https://github.com/angular/angular/commit/3b4d9dc))
@ -29,64 +99,6 @@
## [6.1.9](https://github.com/angular/angular/compare/6.1.8...6.1.9) (2018-09-26) ## [6.1.9](https://github.com/angular/angular/compare/6.1.8...6.1.9) (2018-09-26)
### Bug Fixes
* **service-worker:** do not blow up when caches are unwritable ([#26042](https://github.com/angular/angular/issues/26042)) ([a169743](https://github.com/angular/angular/commit/a169743))
<a name="7.0.0-beta.6"></a>
# [7.0.0-beta.6](https://github.com/angular/angular/compare/7.0.0-beta.5...7.0.0-beta.6) (2018-09-19)
### Bug Fixes
* **bazel:** specify the package and lock files using the workspace ([#25694](https://github.com/angular/angular/issues/25694)) ([ddc1335](https://github.com/angular/angular/commit/ddc1335))
* **common:** register locale data for all equivalent closure locales ([#25867](https://github.com/angular/angular/issues/25867)) ([d83f9d4](https://github.com/angular/angular/commit/d83f9d4))
* **compiler:** Fix look up of entryComponents in AOT Summaries ([#24892](https://github.com/angular/angular/issues/24892)) ([00d3666](https://github.com/angular/angular/commit/00d3666))
* **ivy:** add [@nocollapse](https://github.com/nocollapse) when writing closure-annotated code ([#25775](https://github.com/angular/angular/issues/25775)) ([a0c4b2d](https://github.com/angular/angular/commit/a0c4b2d))
* **ivy:** don't accidently read the inherited definition ([#25736](https://github.com/angular/angular/issues/25736)) ([d5bd86a](https://github.com/angular/angular/commit/d5bd86a)), closes [#24011](https://github.com/angular/angular/issues/24011) [#25026](https://github.com/angular/angular/issues/25026)
* **ivy:** ensure Ivy *Ref classes derive from view engine equivalents ([#25775](https://github.com/angular/angular/issues/25775)) ([a9099e8](https://github.com/angular/angular/commit/a9099e8))
* **ivy:** events should not mark views dirty by default ([#25969](https://github.com/angular/angular/issues/25969)) ([5653874](https://github.com/angular/angular/commit/5653874))
* **ivy:** ngcc should compile entry-points in the correct order ([#25862](https://github.com/angular/angular/issues/25862)) ([9b1bb37](https://github.com/angular/angular/commit/9b1bb37))
* **ivy:** use proper sanitizer names ([#25817](https://github.com/angular/angular/issues/25817)) ([21009b0](https://github.com/angular/angular/commit/21009b0)), closes [#25816](https://github.com/angular/angular/issues/25816)
* **router:** mount correct component if router outlet was not instantiated and if using a route reuse strategy ([#25313](https://github.com/angular/angular/issues/25313)) ([#25314](https://github.com/angular/angular/issues/25314)) ([8dc2b11](https://github.com/angular/angular/commit/8dc2b11))
### Features
* **bazel:** add additional parameters to `ts_api_guardian_test` def ([#25694](https://github.com/angular/angular/issues/25694)) ([2a21ca0](https://github.com/angular/angular/commit/2a21ca0))
* **ivy:** allow combined context discovery for components, directives and elements ([#25754](https://github.com/angular/angular/issues/25754)) ([62be8c2](https://github.com/angular/angular/commit/62be8c2))
* **ivy:** patch animations into metadata ([#25828](https://github.com/angular/angular/issues/25828)) ([d2dfd48](https://github.com/angular/angular/commit/d2dfd48))
* **ivy:** resolve references to vars in .d.ts files ([#25775](https://github.com/angular/angular/issues/25775)) ([96d6b79](https://github.com/angular/angular/commit/96d6b79))
* **ivy:** support animation [@triggers](https://github.com/triggers) in templates ([#25849](https://github.com/angular/angular/issues/25849)) ([e363388](https://github.com/angular/angular/commit/e363388))
* **ivy:** support bootstrap in ngModuleDef ([#25775](https://github.com/angular/angular/issues/25775)) ([13ccdfd](https://github.com/angular/angular/commit/13ccdfd))
<a name="7.0.0-beta.5"></a>
# [7.0.0-beta.5](https://github.com/angular/angular/compare/7.0.0-beta.4...7.0.0-beta.5) (2018-09-06)
### Bug Fixes
* **bazel:** protractor rule should include *.e2e-spec.js ([#25701](https://github.com/angular/angular/issues/25701)) ([3809e0f](https://github.com/angular/angular/commit/3809e0f))
* **benchpress:** Use performance.mark() instead of console.time() ([#24114](https://github.com/angular/angular/issues/24114)) ([06d0400](https://github.com/angular/angular/commit/06d0400))
* **compiler:** add hostVars and support pure functions in host bindings ([#25626](https://github.com/angular/angular/issues/25626)) ([b424b31](https://github.com/angular/angular/commit/b424b31))
* **core:** do not clear element content when using shadow dom ([#24861](https://github.com/angular/angular/issues/24861)) ([6e828bb](https://github.com/angular/angular/commit/6e828bb))
* **core:** size regression with closure compiler ([#25531](https://github.com/angular/angular/issues/25531)) ([1f59f2f](https://github.com/angular/angular/commit/1f59f2f))
* **elements:** add compiler dependency ([#24861](https://github.com/angular/angular/issues/24861)) ([6143da6](https://github.com/angular/angular/commit/6143da6))
* **elements:** add compiler to integration ([#24861](https://github.com/angular/angular/issues/24861)) ([a080ffc](https://github.com/angular/angular/commit/a080ffc))
* **elements:** strict null checks ([#24861](https://github.com/angular/angular/issues/24861)) ([a8210d0](https://github.com/angular/angular/commit/a8210d0))
* **upgrade:** trigger `$destroy` event on upgraded component element ([#25357](https://github.com/angular/angular/issues/25357)) ([2a672a9](https://github.com/angular/angular/commit/2a672a9)), closes [#25334](https://github.com/angular/angular/issues/25334)
### Features
* **elements:** enable Shadow DOM v1 and slots ([#24861](https://github.com/angular/angular/issues/24861)) ([c9844a2](https://github.com/angular/angular/commit/c9844a2))
* **router:** warn if navigation triggered outside Angular zone ([#24959](https://github.com/angular/angular/issues/24959)) ([010e35d](https://github.com/angular/angular/commit/010e35d)), closes [#15770](https://github.com/angular/angular/issues/15770) [#15946](https://github.com/angular/angular/issues/15946) [#24728](https://github.com/angular/angular/issues/24728)
<a name="6.1.7"></a> <a name="6.1.7"></a>
@ -102,18 +114,6 @@
* **router:** warn if navigation triggered outside Angular zone ([#24959](https://github.com/angular/angular/issues/24959)) ([23a96dc](https://github.com/angular/angular/commit/23a96dc)), closes [#15770](https://github.com/angular/angular/issues/15770) [#15946](https://github.com/angular/angular/issues/15946) [#24728](https://github.com/angular/angular/issues/24728) * **router:** warn if navigation triggered outside Angular zone ([#24959](https://github.com/angular/angular/issues/24959)) ([23a96dc](https://github.com/angular/angular/commit/23a96dc)), closes [#15770](https://github.com/angular/angular/issues/15770) [#15946](https://github.com/angular/angular/issues/15946) [#24728](https://github.com/angular/angular/issues/24728)
<a name="7.0.0-beta.4"></a>
# [7.0.0-beta.4](https://github.com/angular/angular/compare/7.0.0-beta.3...7.0.0-beta.4) (2018-08-29)
### Bug Fixes
* **bazel:** Cache fileNameToModuleName lookups ([#25731](https://github.com/angular/angular/issues/25731)) ([f394ba0](https://github.com/angular/angular/commit/f394ba0))
* **bazel:** move bazel managed runtime deps for downstream usage ([#25690](https://github.com/angular/angular/issues/25690)) ([6ed7993](https://github.com/angular/angular/commit/6ed7993))
* **bazel:** only lookup amd module-name tags in .d.ts files ([#25710](https://github.com/angular/angular/issues/25710)) ([42072c4](https://github.com/angular/angular/commit/42072c4))
* **compiler:** update compiler to generate new slot allocations ([#25607](https://github.com/angular/angular/issues/25607)) ([27e2039](https://github.com/angular/angular/commit/27e2039))
<a name="6.1.6"></a> <a name="6.1.6"></a>
## [6.1.6](https://github.com/angular/angular/compare/6.1.5...6.1.6) (2018-08-29) ## [6.1.6](https://github.com/angular/angular/compare/6.1.5...6.1.6) (2018-08-29)
@ -127,14 +127,6 @@
Note: the 6.1.5 release on npm accidentally glitched-out midway, so we cut 6.1.6 instead. sorry! :-) Note: the 6.1.5 release on npm accidentally glitched-out midway, so we cut 6.1.6 instead. sorry! :-)
<a name="7.0.0-beta.3"></a>
# [7.0.0-beta.3](https://github.com/angular/angular/compare/7.0.0-beta.2...7.0.0-beta.3) (2018-08-22)
### Features
* **router:** add UrlSegment[] to CanLoad interface ([#13127](https://github.com/angular/angular/issues/13127)) ([07d8d39](https://github.com/angular/angular/commit/07d8d39)), closes [#12411](https://github.com/angular/angular/issues/12411)
<a name="6.1.4"></a> <a name="6.1.4"></a>
@ -147,15 +139,6 @@ Note: the 6.1.5 release on npm accidentally glitched-out midway, so we cut 6.1.6
<a name="7.0.0-beta.2"></a>
# [7.0.0-beta.2](https://github.com/angular/angular/compare/7.0.0-beta.1...7.0.0-beta.2) (2018-08-15)
### Bug Fixes
* **bazel:** correct type concatenated to devmode_js ([#25467](https://github.com/angular/angular/issues/25467)) ([fb2c524](https://github.com/angular/angular/commit/fb2c524))
<a name="6.1.3"></a> <a name="6.1.3"></a>
## [6.1.3](https://github.com/angular/angular/compare/6.1.2...6.1.3) (2018-08-15) ## [6.1.3](https://github.com/angular/angular/compare/6.1.2...6.1.3) (2018-08-15)
@ -166,24 +149,6 @@ Note: the 6.1.5 release on npm accidentally glitched-out midway, so we cut 6.1.6
<a name="7.0.0-beta.1"></a>
# [7.0.0-beta.1](https://github.com/angular/angular/compare/7.0.0-beta.0...7.0.0-beta.1) (2018-08-08)
### Bug Fixes
* **compiler-cli:** use the oldProgram option in watch mode ([#21364](https://github.com/angular/angular/issues/21364)) ([c6e5b97](https://github.com/angular/angular/commit/c6e5b97)), closes [#21361](https://github.com/angular/angular/issues/21361)
* **core:** In Testability.whenStable update callback, pass more complete ([#25010](https://github.com/angular/angular/issues/25010)) ([16c03c0](https://github.com/angular/angular/commit/16c03c0))
* add mappings for ngfactory & ngsummary files to their module names in aot summary resolver ([#25335](https://github.com/angular/angular/issues/25335)) ([02e201a](https://github.com/angular/angular/commit/02e201a))
* **router:** take base uri into account in `setUpLocationSync()` ([#20244](https://github.com/angular/angular/issues/20244)) ([ba1e25f](https://github.com/angular/angular/commit/ba1e25f)), closes [#20061](https://github.com/angular/angular/issues/20061)
### Features
* **core:** add DoBootstrap interface. ([#24558](https://github.com/angular/angular/issues/24558)) ([732026c](https://github.com/angular/angular/commit/732026c)), closes [#24557](https://github.com/angular/angular/issues/24557)
<a name="6.1.2"></a> <a name="6.1.2"></a>
## [6.1.2](https://github.com/angular/angular/compare/6.1.1...6.1.2) (2018-08-08) ## [6.1.2](https://github.com/angular/angular/compare/6.1.1...6.1.2) (2018-08-08)
@ -194,22 +159,6 @@ Note: the 6.1.5 release on npm accidentally glitched-out midway, so we cut 6.1.6
* add mappings for ngfactory & ngsummary files to their module names in aot summary resolver ([#25335](https://github.com/angular/angular/issues/25335)) ([054fbbe](https://github.com/angular/angular/commit/054fbbe)) * add mappings for ngfactory & ngsummary files to their module names in aot summary resolver ([#25335](https://github.com/angular/angular/issues/25335)) ([054fbbe](https://github.com/angular/angular/commit/054fbbe))
<a name="7.0.0-beta.0"></a>
# [7.0.0-beta.0](https://github.com/angular/angular/compare/6.1.0...7.0.0-beta.0) (2018-08-02)
### Bug Fixes
* **bazel:** allow compile_strategy to be (privately) imported ([#25080](https://github.com/angular/angular/issues/25080)) ([0d1d589](https://github.com/angular/angular/commit/0d1d589))
* **compiler:** update compiler to flatten nested template fns ([#24943](https://github.com/angular/angular/issues/24943)) ([fe14f18](https://github.com/angular/angular/commit/fe14f18))
* **compiler-cli:** correct realPath to realpath. ([#25023](https://github.com/angular/angular/issues/25023)) ([01e6dab](https://github.com/angular/angular/commit/01e6dab))
* **core:** throw error message when @Output not initialized ([#19116](https://github.com/angular/angular/issues/19116)) ([adf510f](https://github.com/angular/angular/commit/adf510f)), closes [#3664](https://github.com/angular/angular/issues/3664)
### Features
* **compiler:** add "original" placeholder value on extracted XMB ([#25079](https://github.com/angular/angular/issues/25079)) ([e99d860](https://github.com/angular/angular/commit/e99d860))
<a name="6.1.1"></a> <a name="6.1.1"></a>
## [6.1.1](https://github.com/angular/angular/compare/6.1.0...6.1.1) (2018-08-02) ## [6.1.1](https://github.com/angular/angular/compare/6.1.0...6.1.1) (2018-08-02)

View File

@ -71,6 +71,8 @@ Before you submit your Pull Request (PR) consider the following guidelines:
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR 1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR
that relates to your submission. You don't want to duplicate effort. that relates to your submission. You don't want to duplicate effort.
1. Be sure that an issue describes the problem you're fixing, or documents the design for the feature you'd like to add.
Discussing the design up front helps to ensure that we're ready to accept your work.
1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs. 1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
We cannot accept code without this. Make sure you sign with the primary email address of the Git identity that has been granted access to the Angular repository. We cannot accept code without this. Make sure you sign with the primary email address of the Git identity that has been granted access to the Angular repository.
1. Fork the angular/angular repo. 1. Fork the angular/angular repo.

View File

@ -13,12 +13,10 @@ Angular is a development platform for building mobile and desktop web applicatio
[Get started in 5 minutes][quickstart]. [Get started in 5 minutes][quickstart].
## Changelog ## Changelog
[Learn about the latest improvements][changelog]. [Learn about the latest improvements][changelog].
## Want to help? ## Want to help?
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our

View File

@ -6,6 +6,16 @@ load(
"rules_angular_dev_dependencies", "rules_angular_dev_dependencies",
) )
# Uncomment for local bazel rules development
#local_repository(
# name = "build_bazel_rules_nodejs",
# path = "../rules_nodejs",
#)
#local_repository(
# name = "build_bazel_rules_typescript",
# path = "../rules_typescript",
#)
# Angular Bazel users will call this function # Angular Bazel users will call this function
rules_angular_dependencies() rules_angular_dependencies()
# These are the dependencies only for us # These are the dependencies only for us

View File

@ -36,6 +36,11 @@ server {
access_log {{$AIO_NGINX_LOGS_DIR}}/access.log; access_log {{$AIO_NGINX_LOGS_DIR}}/access.log;
error_log {{$AIO_NGINX_LOGS_DIR}}/error.log; error_log {{$AIO_NGINX_LOGS_DIR}}/error.log;
error_page 404 /404.html;
location "=/404.html" {
internal;
}
location "~/[^/]+\.[^/]+$" { location "~/[^/]+\.[^/]+$" {
try_files $uri $uri/ =404; try_files $uri $uri/ =404;
} }

View File

@ -3,7 +3,7 @@
TODO (gkalpak): Add docs. Mention: TODO (gkalpak): Add docs. Mention:
- Testing on CI. - Testing on CI.
Relevant files: `scripts/ci/test-aio.sh`, `aio/aio-builds-setup/scripts/test.sh` Relevant files: `aio/aio-builds-setup/scripts/test.sh`
- Deploying from CI. - Deploying from CI.
Relevant files: `.circleci/config.yml`, `scripts/ci/deploy.sh`, `aio/scripts/build-artifacts.sh`, Relevant files: `.circleci/config.yml`, `scripts/ci/deploy.sh`, `aio/scripts/build-artifacts.sh`,
`aio/scripts/deploy-to-firebase.sh` `aio/scripts/deploy-to-firebase.sh`

View File

@ -1 +1,3 @@
yarn.lock /node_modules
package.json
yarn.lock

View File

@ -1,5 +0,0 @@
{
"dependencies": {
"@angular/cli": "https://github.com/angular/cli-builds#master"
}
}

View File

@ -1,83 +1,100 @@
<h1 class="no-toc">CLI Command Reference</h1> <h1 class="no-toc">CLI Command Reference</h1>
The Angular CLI is a command-line tool that you use to initialize, develop, scaffold, and maintain Angular applications. The Angular CLI is a command-line interface tool that you use to initialize, develop, scaffold, and maintain Angular applications. You can use the tool directly in a command shell, or indirectly through an interactive UI such as [Angular Console](https://angularconsole.com).
## Getting Started ## Installing Angular CLI
### Installing Angular CLI Major versions of Angular CLI follow the supported major version of Angular, but minor versions can be released separately.
The current version of Angular CLI is 6.x. Install the CLI using the `npm` package manager:
<code-example format="." language="bash">
npm install -g @angular/cli
</code-example>
* Both the CLI and the projects that you generate with the tool have dependencies that require Node 8.9 or higher, together with NPM 5.5.1 or higher. For details about changes between versions, and information about updating from previous releases,
* Install the CLI using npm: see the Releases tab on GitHub: https://github.com/angular/angular-cli/releases
`npm install -g @angular/cli`
* The CLI is an open-source tool:
https://github.com/angular/angular-cli/tree/master/packages/angular/cli
For details about changes between versions, and information about updating from previous releases, see the Releases tab on GitHub. ## Basic workflow
### Basic workflow 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.
Invoke the tool on the command line through the ng executable. Online help is available on the command line: <code-example format="." 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:
> ng help Lists commands with short descriptions
> ng <command> --help Lists options for a command.
```
To create, build, and serve a new, basic Angular project on a development server, use the following commands: <code-example format="." language="bash">
ng new my-first-project
``` cd my-first-project
cd <parent of new workspace>
ng new my-project
cd my-project
ng serve ng serve
``` </code-example>
In your browser, open http://localhost:4200/ to see the new app run. In your browser, open http://localhost:4200/ to see the new app run.
### Workspaces and project files ## Workspaces and project files
Angular 6 introduced the workspace directory structure for Angular apps. A workspace defines a project. A project can contain multiple apps, as well as libraries that can be used in any of the apps. The [ng new](cli/new) command creates an *Angular workspace* folder and generates a new app skeleton.
A workspace can contain multiple apps and libraries.
The initial app created by the [ng new](cli/new) command is at the top level of the workspace.
When you generate an additional app or library in a workspace, it goes into a `projects/` subfolder.
Some commands (such as build) must be executed from within a workspace folder, and others (such as new) must be executed from outside any workspace. This requirement is called out in the description of each command where it applies.The `new` command creates a [workspace](guide/glossary#workspace) to contain [projects](guide/glossary#project). A project can be an app or a library, and a workspace can contain multiple apps and libraries. A newly generated app contains the source files for a root module, with a root component and template.
Each app has a `src` folder that contains the logic, data, and assets.
A newly generated app project contains the source files for a root module, with a root component and template, which you can edit directly, or add to and modify using CLI commands. Use the generate command to add new files for additional components and services, and code for new pipes, directives, and so on. You can edit the generated files directly, or add to and modify them using CLI commands.
Use the [ng generate](cli/generate) command to add new files for additional components and services, and code for new pipes, directives, and so on.
Commands such as [add](cli/add) and [generate](cli/generate), which create or operate on apps and libraries, must be executed from within a workspace or project folder.
* Commands such as `add` and `generate`, that create or operate on apps and libraries, must be executed from within a workspace folder. * See more about the [Workspace file structure](guide/file-structure).
* Apps in a workspace can use libraries in the same workspace.
* Each project has a `src` folder that contains the logic, data, and assets.
See an example of the [file structure](guide/quickstart#project-file-review) in [Getting Started](guide/quickstart).
When you use the `serve` command to build an app, the server automatically rebuilds the app and reloads the page when you change any of the source files. When you use the [ng serve](cli/serve) command to build an app and serve it locally, the server automatically rebuilds the app and reloads the page when you change any of the source files.
### Configuring the CLI A single workspace configuration file, `angular.json`, is created at the top level of the workspace.
This is where you can set workspace-wide defaults, and specify configurations to use when the CLI builds a project for different targets.
Configuration files let you customize your project. The CLI configuration file, angular.json, is created at the top level of the project folder. This is where you can set CLI defaults for your project, and specify which files to include when the CLI builds the project. The [ng config](cli/config) command lets you set and retrieve configuration values from the command line, or you can edit the `angular.json` file directly.
The CLI config command lets you set and retrieve configuration values from the command line, or you can edit the angular.json file directly. * See the [complete schema](https://github.com/angular/angular-cli/wiki/angular-workspace) for `angular.json`.
<!-- * Learn more about *configuration options for Angular(links to new guide or topics TBD)*. -->
* See the complete schema for angular.json.
* Learn more about configuration options for Angular (link to new guide?)
### Command options and arguments ## CLI command-language syntax
All commands and some options have aliases, as listed in the descriptions. Option names are prefixed with a double dash (--), but arguments and option aliases are not.
Typically, the name of a generated artifact can be given as an argument to the command or specified with the --name option. Most commands have additional options.
Command syntax is shown as follows: Command syntax is shown as follows:
``` `ng` *commandNameOrAlias* *requiredArg* [*optionalArg*] `[options]`
ng commandNameOrAlias <arg> [options]
```
Options take either string or Boolean arguments. Defaults are shown in bold for Boolean or enumerated values, and are given with the description. For example: * Most commands, and some options, have aliases. Aliases are shown in the syntax statement for each command.
``` * Option names are prefixed with a double dash (--).
--optionNameOrAlias=<filename> Option aliases are prefixed with a single dash (-).
--optionNameOrAlias=true|false Arguments are not prefixed.
--optionNameOrAlias=allowedValue1|allowedValue2|allowedValue3 For example: `ng build my-app -c production`
```
* Typically, the name of a generated artifact can be given as an argument to the command or specified with the --name option.
* Argument and option names can be given in either
[camelCase or dash-case](guide/glossary#case-types).
`--myOptionName` is equivalent to `--my-option-name`.
### Boolean and enumerated options
Boolean options have two forms: `--thisOption` sets the flag, `--noThisOption` clears it.
If neither option is supplied, the flag remains in its default state, as listed in the reference documentation.
Allowed values are given with each enumerated option description, with the default value in **bold**.
### Relative paths
Options that specify files can be given as absolute paths, or as paths relative to the current working directory, which is generally either the workspace or project root.
### Schematics
The [ng generate](cli/generate) and [ng add](cli/add) commands take as an argument the artifact or library to be generated or added to the current project.
In addition to any general options, each artifact or library defines its own options in a *schematic*.
Schematic options are supplied to the command in the same format as immediate command options.
Boolean options can also be expressed with a prefix `no-` to indicate a value of false. For example, `--no-prod` is equivalent to `--prod=false`.

View File

@ -1,6 +1,6 @@
'use strict'; // necessary for es6 output in node 'use strict'; // necessary for es6 output in node
import { browser } from 'protractor'; import { browser, ExpectedConditions as EC } from 'protractor';
import { logging } from 'selenium-webdriver'; import { logging } from 'selenium-webdriver';
import * as openClose from './open-close.po'; import * as openClose from './open-close.po';
import * as statusSlider from './status-slider.po'; import * as statusSlider from './status-slider.po';
@ -25,6 +25,8 @@ describe('Animation Tests', () => {
}); });
describe('Open/Close Component', () => { describe('Open/Close Component', () => {
const closedHeight = '100px';
const openHeight = '200px';
beforeAll(async () => { beforeAll(async () => {
await openCloseHref.click(); await openCloseHref.click();
@ -32,37 +34,37 @@ describe('Animation Tests', () => {
}); });
it('should be open', async () => { it('should be open', async () => {
let text = await openClose.getComponentText();
const toggleButton = openClose.getToggleButton(); const toggleButton = openClose.getToggleButton();
const container = openClose.getComponentContainer(); const container = openClose.getComponentContainer();
let text = await container.getText();
if (text.includes('Closed')) { if (text.includes('Closed')) {
await toggleButton.click(); await toggleButton.click();
sleepFor(); await browser.wait(async () => await container.getCssValue('height') === openHeight, 2000);
} }
text = await openClose.getComponentText(); text = await container.getText();
const containerHeight = await container.getCssValue('height'); const containerHeight = await container.getCssValue('height');
expect(text).toContain('The box is now Open!'); expect(text).toContain('The box is now Open!');
expect(containerHeight).toBe('200px'); expect(containerHeight).toBe(openHeight);
}); });
it('should be closed', async () => { it('should be closed', async () => {
let text = await openClose.getComponentText();
const toggleButton = openClose.getToggleButton(); const toggleButton = openClose.getToggleButton();
const container = openClose.getComponentContainer(); const container = openClose.getComponentContainer();
let text = await container.getText();
if (text.includes('Open')) { if (text.includes('Open')) {
await toggleButton.click(); await toggleButton.click();
sleepFor(); await browser.wait(async () => await container.getCssValue('height') === closedHeight, 2000);
} }
text = await openClose.getComponentText(); text = await container.getText();
const containerHeight = await container.getCssValue('height'); const containerHeight = await container.getCssValue('height');
expect(text).toContain('The box is now Closed!'); expect(text).toContain('The box is now Closed!');
expect(containerHeight).toBe('100px'); expect(containerHeight).toBe(closedHeight);
}); });
it('should log animation events', async () => { it('should log animation events', async () => {
@ -72,8 +74,7 @@ describe('Animation Tests', () => {
await toggleButton.click(); await toggleButton.click();
const logs = await browser.manage().logs().get(logging.Type.BROWSER); const logs = await browser.manage().logs().get(logging.Type.BROWSER);
const animationMessages = logs.filter(({ message }) => message.includes('Animation'));
const animationMessages = logs.filter(({ message }) => message.indexOf('Animation') !== -1 ? true : false);
expect(animationMessages.length).toBeGreaterThan(0); expect(animationMessages.length).toBeGreaterThan(0);
}); });
@ -89,16 +90,16 @@ describe('Animation Tests', () => {
}); });
it('should be inactive with an orange background', async () => { it('should be inactive with an orange background', async () => {
let text = await statusSlider.getComponentText();
const toggleButton = statusSlider.getToggleButton(); const toggleButton = statusSlider.getToggleButton();
const container = statusSlider.getComponentContainer(); const container = statusSlider.getComponentContainer();
let text = await container.getText();
if (text === 'Active') { if (text === 'Active') {
await toggleButton.click(); await toggleButton.click();
sleepFor(2000); await browser.wait(async () => await container.getCssValue('backgroundColor') === inactiveColor, 2000);
} }
text = await statusSlider.getComponentText(); text = await container.getText();
const bgColor = await container.getCssValue('backgroundColor'); const bgColor = await container.getCssValue('backgroundColor');
expect(text).toBe('Inactive'); expect(text).toBe('Inactive');
@ -106,16 +107,16 @@ describe('Animation Tests', () => {
}); });
it('should be active with a blue background', async () => { it('should be active with a blue background', async () => {
let text = await statusSlider.getComponentText();
const toggleButton = statusSlider.getToggleButton(); const toggleButton = statusSlider.getToggleButton();
const container = statusSlider.getComponentContainer(); const container = statusSlider.getComponentContainer();
let text = await container.getText();
if (text === 'Inactive') { if (text === 'Inactive') {
await toggleButton.click(); await toggleButton.click();
sleepFor(2000); await browser.wait(async () => await container.getCssValue('backgroundColor') === activeColor, 2000);
} }
text = await statusSlider.getComponentText(); text = await container.getText();
const bgColor = await container.getCssValue('backgroundColor'); const bgColor = await container.getCssValue('backgroundColor');
expect(text).toBe('Active'); expect(text).toBe('Active');
@ -163,10 +164,7 @@ describe('Animation Tests', () => {
const hero = heroesList.get(0); const hero = heroesList.get(0);
await hero.click(); await hero.click();
await sleepFor(100); await browser.wait(async () => await heroesList.count() < total, 2000);
const newTotal = await heroesList.count();
expect(newTotal).toBeLessThan(total);
}); });
}); });
@ -190,10 +188,7 @@ describe('Animation Tests', () => {
const hero = heroesList.get(0); const hero = heroesList.get(0);
await hero.click(); await hero.click();
await sleepFor(250); await browser.wait(async () => await heroesList.count() < total, 2000);
const newTotal = await heroesList.count();
expect(newTotal).toBeLessThan(total);
}); });
}); });
@ -213,14 +208,14 @@ describe('Animation Tests', () => {
it('should filter down the list when a search is performed', async () => { it('should filter down the list when a search is performed', async () => {
const heroesList = filterStagger.getHeroesList(); const heroesList = filterStagger.getHeroesList();
const total = await heroesList.count(); const total = await heroesList.count();
const formInput = filterStagger.getFormInput(); const formInput = filterStagger.getFormInput();
await formInput.sendKeys('Mag'); await formInput.sendKeys('Mag');
await sleepFor(500);
const newTotal = await heroesList.count();
await browser.wait(async () => await heroesList.count() === 2, 2000);
const newTotal = await heroesList.count();
expect(newTotal).toBeLessThan(total); expect(newTotal).toBeLessThan(total);
expect(newTotal).toBe(2);
}); });
}); });
@ -248,10 +243,7 @@ describe('Animation Tests', () => {
const hero = heroesList.get(0); const hero = heroesList.get(0);
await hero.click(); await hero.click();
await sleepFor(300); await browser.wait(async () => await heroesList.count() < total, 2000);
const newTotal = await heroesList.count();
expect(newTotal).toBeLessThan(total);
}); });
}); });
}); });

View File

@ -23,11 +23,3 @@ export function getComponentContainer() {
const findContainer = () => by.css('div'); const findContainer = () => by.css('div');
return locate(getComponent(), findContainer()); return locate(getComponent(), findContainer());
} }
export async function getComponentText() {
const findContainerText = () => by.css('div');
const contents = locate(getComponent(), findContainerText());
const componentText = await contents.getText();
return componentText;
}

View File

@ -18,11 +18,3 @@ export function getComponentContainer() {
const findContainer = () => by.css('div'); const findContainer = () => by.css('div');
return locate(getComponent(), findContainer()); return locate(getComponent(), findContainer());
} }
export async function getComponentText() {
const findContainerText = () => by.css('div');
const contents = locate(getComponent(), findContainerText());
const componentText = await contents.getText();
return componentText;
}

View File

@ -2,7 +2,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
// #enddocregion import // #enddocregion import
// #docregion metadata // #docregion metadata, component
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
templateUrl: './app.component.html', templateUrl: './app.component.html',
@ -13,4 +13,4 @@ import { Component } from '@angular/core';
export class AppComponent { export class AppComponent {
title = 'My First Angular App!'; title = 'My First Angular App!';
} }
// #enddocregion title, class // #enddocregion title, class, component

View File

@ -1,12 +1,23 @@
'use strict'; // necessary for es6 output in node 'use strict'; // necessary for es6 output in node
import { browser, by, element } from 'protractor'; import { browser, by, element, ElementFinder, ExpectedConditions as EC } from 'protractor';
/* tslint:disable:quotemark */ /* tslint:disable:quotemark */
describe('Elements', () => { describe('Elements', () => {
const messageInput = element(by.css('input')); const messageInput = element(by.css('input'));
const popupButtons = element.all(by.css('button')); const popupButtons = element.all(by.css('button'));
// Helpers
const click = (elem: ElementFinder) => {
// Waiting for the element to be clickable, makes the tests less flaky.
browser.wait(EC.elementToBeClickable(elem), 5000);
elem.click();
};
const waitForText = (elem: ElementFinder) => {
// Waiting for the element to have some text, makes the tests less flaky.
browser.wait(async () => /\S/.test(await elem.getText()), 5000);
}
beforeEach(() => browser.get('')); beforeEach(() => browser.get(''));
describe('popup component', () => { describe('popup component', () => {
@ -17,7 +28,7 @@ describe('Elements', () => {
it('should be displayed on button click', () => { it('should be displayed on button click', () => {
expect(popupComponent.isPresent()).toBe(false); expect(popupComponent.isPresent()).toBe(false);
popupComponentButton.click(); click(popupComponentButton);
expect(popupComponent.isPresent()).toBe(true); expect(popupComponent.isPresent()).toBe(true);
}); });
@ -25,7 +36,9 @@ describe('Elements', () => {
messageInput.clear(); messageInput.clear();
messageInput.sendKeys('Angular rocks!'); messageInput.sendKeys('Angular rocks!');
popupComponentButton.click(); click(popupComponentButton);
waitForText(popupComponent);
expect(popupComponent.getText()).toContain('Popup: Angular rocks!'); expect(popupComponent.getText()).toContain('Popup: Angular rocks!');
}); });
@ -33,7 +46,7 @@ describe('Elements', () => {
popupComponentButton.click(); popupComponentButton.click();
expect(popupComponent.isPresent()).toBe(true); expect(popupComponent.isPresent()).toBe(true);
closeButton.click(); click(closeButton);
expect(popupComponent.isPresent()).toBe(false); expect(popupComponent.isPresent()).toBe(false);
}); });
}); });
@ -46,7 +59,7 @@ describe('Elements', () => {
it('should be displayed on button click', () => { it('should be displayed on button click', () => {
expect(popupElement.isPresent()).toBe(false); expect(popupElement.isPresent()).toBe(false);
popupElementButton.click(); click(popupElementButton);
expect(popupElement.isPresent()).toBe(true); expect(popupElement.isPresent()).toBe(true);
}); });
@ -54,7 +67,9 @@ describe('Elements', () => {
messageInput.clear(); messageInput.clear();
messageInput.sendKeys('Angular rocks!'); messageInput.sendKeys('Angular rocks!');
popupElementButton.click(); click(popupElementButton);
waitForText(popupElement);
expect(popupElement.getText()).toContain('Popup: Angular rocks!'); expect(popupElement.getText()).toContain('Popup: Angular rocks!');
}); });
@ -62,7 +77,7 @@ describe('Elements', () => {
popupElementButton.click(); popupElementButton.click();
expect(popupElement.isPresent()).toBe(true); expect(popupElement.isPresent()).toBe(true);
closeButton.click(); click(closeButton);
expect(popupElement.isPresent()).toBe(false); expect(popupElement.isPresent()).toBe(false);
}); });
}); });

View File

@ -8,11 +8,11 @@ import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [ const routes: Routes = [
{ {
path: 'customers', path: 'customers',
loadChildren: 'app/customers/customers.module#CustomersModule' loadChildren: './customers/customers.module#CustomersModule'
}, },
{ {
path: 'orders', path: 'orders',
loadChildren: 'app/orders/orders.module#OrdersModule' loadChildren: './orders/orders.module#OrdersModule'
}, },
{ {
path: '', path: '',

View File

@ -5,8 +5,8 @@ import { ContactModule } from './contact/contact.module.3';
const routes: Routes = [ const routes: Routes = [
{ path: '', redirectTo: 'contact', pathMatch: 'full'}, { path: '', redirectTo: 'contact', pathMatch: 'full'},
{ path: 'crisis', loadChildren: 'app/crisis/crisis.module#CrisisModule' }, { path: 'crisis', loadChildren: './crisis/crisis.module#CrisisModule' },
{ path: 'heroes', loadChildren: 'app/hero/hero.module.3#HeroModule' } { path: 'heroes', loadChildren: './hero/hero.module.3#HeroModule' }
]; ];
@NgModule({ @NgModule({

View File

@ -8,8 +8,8 @@ import { ContactModule } from './contact/contact.module';
const routes: Routes = [ const routes: Routes = [
{ path: '', redirectTo: 'contact', pathMatch: 'full'}, { path: '', redirectTo: 'contact', pathMatch: 'full'},
// #docregion lazy-routes // #docregion lazy-routes
{ path: 'crisis', loadChildren: 'app/crisis/crisis.module#CrisisModule' }, { path: 'crisis', loadChildren: './crisis/crisis.module#CrisisModule' },
{ path: 'heroes', loadChildren: 'app/hero/hero.module#HeroModule' } { path: 'heroes', loadChildren: './hero/hero.module#HeroModule' }
// #enddocregion lazy-routes // #enddocregion lazy-routes
]; ];
// #enddocregion routes // #enddocregion routes

View File

@ -3,8 +3,8 @@ import { Routes, RouterModule } from '@angular/router';
export const routes: Routes = [ export const routes: Routes = [
{ path: '', redirectTo: 'contact', pathMatch: 'full'}, { path: '', redirectTo: 'contact', pathMatch: 'full'},
{ path: 'items', loadChildren: 'app/items/items.module#ItemsModule' }, { path: 'items', loadChildren: './items/items.module#ItemsModule' },
{ path: 'customers', loadChildren: 'app/customers/customers.module#CustomersModule' } { path: 'customers', loadChildren: './customers/customers.module#CustomersModule' }
]; ];
@NgModule({ @NgModule({

View File

@ -4,7 +4,7 @@ import { Observable, of } from 'rxjs';
// #docregion observer // #docregion observer
// Create simple observable that emits three values // Create simple observable that emits three values
const myObservable = Observable.of(1, 2, 3); const myObservable = of(1, 2, 3);
// Create observer object // Create observer object
const myObserver = { const myObserver = {

View File

@ -35,14 +35,14 @@ describe('Reactive forms', function () {
it('should update the name control when the Update Name button is clicked', async () => { it('should update the name control when the Update Name button is clicked', async () => {
await nameInput.sendKeys(nameText); await nameInput.sendKeys(nameText);
const value = await nameInput.getAttribute('value'); const value1 = await nameInput.getAttribute('value');
expect(value).toBe(nameText); expect(value1).toBe(nameText);
await updateButton.click(); await updateButton.click();
const value = await nameInput.getAttribute('value'); const value2 = await nameInput.getAttribute('value');
expect(value).toBe('Nancy'); expect(value2).toBe('Nancy');
}); });
it('should update the displayed control value when the name control updated', async () => { it('should update the displayed control value when the name control updated', async () => {

View File

@ -8,7 +8,7 @@ import { AboutComponent } from './about/about.component';
RouterModule.forRoot([ RouterModule.forRoot([
{ path: '', redirectTo: 'dashboard', pathMatch: 'full'}, { path: '', redirectTo: 'dashboard', pathMatch: 'full'},
{ path: 'about', component: AboutComponent }, { path: 'about', component: AboutComponent },
{ path: 'heroes', loadChildren: 'app/hero/hero.module#HeroModule'} { path: 'heroes', loadChildren: './hero/hero.module#HeroModule'}
]) ])
], ],
exports: [ RouterModule ] // re-export the module declarations exports: [ RouterModule ] // re-export the module declarations

View File

@ -1,8 +1,7 @@
// tslint:disable-next-line:no-unused-variable // tslint:disable-next-line:no-unused-variable
import { async, fakeAsync, tick } from '@angular/core/testing'; import { async, fakeAsync, tick } from '@angular/core/testing';
import { interval, of } from 'rxjs';
import { of } from 'rxjs'; import { delay, take } from 'rxjs/operators';
import { delay } from 'rxjs/operators';
describe('Angular async helper', () => { describe('Angular async helper', () => {
let actuallyDone = false; let actuallyDone = false;
@ -21,49 +20,120 @@ describe('Angular async helper', () => {
}); });
it('should run async test with task', it('should run async test with task',
async(() => { setTimeout(() => { actuallyDone = true; }, 0); })); async(() => { setTimeout(() => { actuallyDone = true; }, 0); }));
it('should run async test with task', async(() => {
const id = setInterval(() => {
actuallyDone = true;
clearInterval(id);
}, 100);
}));
it('should run async test with successful promise', async(() => { it('should run async test with successful promise', async(() => {
const p = new Promise(resolve => { setTimeout(resolve, 10); }); const p = new Promise(resolve => { setTimeout(resolve, 10); });
p.then(() => { actuallyDone = true; }); p.then(() => { actuallyDone = true; });
})); }));
it('should run async test with failed promise', async(() => { it('should run async test with failed promise', async(() => {
const p = new Promise((resolve, reject) => { setTimeout(reject, 10); }); const p = new Promise((resolve, reject) => { setTimeout(reject, 10); });
p.catch(() => { actuallyDone = true; }); p.catch(() => { actuallyDone = true; });
})); }));
// Use done. Cannot use setInterval with async or fakeAsync // Use done. Can also use async or fakeAsync.
// See https://github.com/angular/angular/issues/10127
it('should run async test with successful delayed Observable', (done: DoneFn) => { it('should run async test with successful delayed Observable', (done: DoneFn) => {
const source = of(true).pipe(delay(10)); const source = of (true).pipe(delay(10));
source.subscribe( source.subscribe(val => actuallyDone = true, err => fail(err), done);
val => actuallyDone = true,
err => fail(err),
done
);
}); });
// Cannot use setInterval from within an async zone test // #docregion fake-async-test-tick
// See https://github.com/angular/angular/issues/10127 it('should run timeout callback with delay after call tick with millis', fakeAsync(() => {
// xit('should run async test with successful delayed Observable', async(() => { let called = false;
// const source = of(true).pipe(delay(10)); setTimeout(() => { called = true; }, 100);
// source.subscribe( tick(100);
// val => actuallyDone = true, expect(called).toBe(true);
// err => fail(err) }));
// ); // #enddocregion fake-async-test-tick
// }));
// // Fail message: Error: 1 periodic timer(s) still in the queue // #docregion fake-async-test-date
// // See https://github.com/angular/angular/issues/10127 it('should get Date diff correctly in fakeAsync', fakeAsync(() => {
// xit('should run async test with successful delayed Observable', fakeAsync(() => { const start = Date.now();
// const source = of(true).pipe(delay(10)); tick(100);
// source.subscribe( const end = Date.now();
// val => actuallyDone = true, expect(end - start).toBe(100);
// err => fail(err) }));
// ); // #enddocregion fake-async-test-date
// tick(); // #docregion fake-async-test-rxjs
// })); it('should get Date diff correctly in fakeAsync with rxjs scheduler', fakeAsync(() => {
// need to add `import 'zone.js/dist/zone-patch-rxjs-fake-async'
// to patch rxjs scheduler
let result = null;
of ('hello').pipe(delay(1000)).subscribe(v => { result = v; });
expect(result).toBeNull();
tick(1000);
expect(result).toBe('hello');
const start = new Date().getTime();
let dateDiff = 0;
interval(1000).pipe(take(2)).subscribe(() => dateDiff = (new Date().getTime() - start));
tick(1000);
expect(dateDiff).toBe(1000);
tick(1000);
expect(dateDiff).toBe(2000);
}));
// #enddocregion fake-async-test-rxjs
// #docregion fake-async-test-clock
describe('use jasmine.clock()', () => {
// need to config __zone_symbol__fakeAsyncPatchLock flag
// before loading zone.js/dist/zone-testing
beforeEach(() => { jasmine.clock().install(); });
afterEach(() => { jasmine.clock().uninstall(); });
it('should auto enter fakeAsync', () => {
// is in fakeAsync now, don't need to call fakeAsync(testFn)
let called = false;
setTimeout(() => { called = true; }, 100);
jasmine.clock().tick(100);
expect(called).toBe(true);
});
});
// #enddocregion fake-async-test-clock
// #docregion async-test-promise-then
describe('test jsonp', () => {
function jsonp(url: string, callback: Function) {
// do a jsonp call which is not zone aware
}
// need to config __zone_symbol__supportWaitUnResolvedChainedPromise flag
// before loading zone.js/dist/zone-testing
it('should wait until promise.then is called', async(() => {
let finished = false;
new Promise((res, rej) => {
jsonp('localhost:8080/jsonp', () => {
// success callback and resolve the promise
finished = true;
res();
});
}).then(() => {
// async will wait until promise.then is called
// if __zone_symbol__supportWaitUnResolvedChainedPromise is set
expect(finished).toBe(true);
});
}));
});
// #enddocregion async-test-promise-then
it('should run async test with successful delayed Observable', async(() => {
const source = of (true).pipe(delay(10));
source.subscribe(val => actuallyDone = true, err => fail(err));
}));
it('should run async test with successful delayed Observable', fakeAsync(() => {
const source = of (true).pipe(delay(10));
source.subscribe(val => actuallyDone = true, err => fail(err));
tick(10);
}));
}); });

View File

@ -12,7 +12,7 @@ h2, h3 {
body { body {
margin: 2em; margin: 2em;
} }
body, input[text], button { body, input[type="text"], button {
color: #888; color: #888;
font-family: Cambria, Georgia; font-family: Cambria, Georgia;
} }

View File

@ -40,7 +40,7 @@ export class HeroService {
// #enddocregion getHeroes-1 // #enddocregion getHeroes-1
.pipe( .pipe(
// #enddocregion getHeroes-2 // #enddocregion getHeroes-2
tap(heroes => this.log('fetched heroes')), tap(_ => this.log('fetched heroes')),
// #docregion getHeroes-2 // #docregion getHeroes-2
catchError(this.handleError('getHeroes', [])) catchError(this.handleError('getHeroes', []))
); );

View File

@ -1,6 +1,6 @@
'use strict'; // necessary for es6 output in node 'use strict'; // necessary for es6 output in node
import { browser, element, by, ElementFinder } from 'protractor'; import { browser, element, by, ElementArrayFinder, ElementFinder } from 'protractor';
// Angular E2E Testing Guide: // Angular E2E Testing Guide:
// https://docs.angularjs.org/guide/e2e-testing // https://docs.angularjs.org/guide/e2e-testing
@ -20,6 +20,12 @@ describe('PhoneCat Application', function() {
describe('View: Phone list', function() { describe('View: Phone list', function() {
// Helpers
const waitForCount = (elems: ElementArrayFinder, count: number) => {
// Wait for the list to stabilize, which may take a while (e.g. due to animations).
browser.wait(() => elems.count().then(c => c === count), 5000);
};
beforeEach(function() { beforeEach(function() {
browser.get('index.html#!/phones'); browser.get('index.html#!/phones');
}); });
@ -28,13 +34,16 @@ describe('PhoneCat Application', function() {
let phoneList = element.all(by.repeater('phone in $ctrl.phones')); let phoneList = element.all(by.repeater('phone in $ctrl.phones'));
let query = element(by.model('$ctrl.query')); let query = element(by.model('$ctrl.query'));
waitForCount(phoneList, 20);
expect(phoneList.count()).toBe(20); expect(phoneList.count()).toBe(20);
query.sendKeys('nexus'); query.sendKeys('nexus');
waitForCount(phoneList, 1);
expect(phoneList.count()).toBe(1); expect(phoneList.count()).toBe(1);
query.clear(); query.clear();
query.sendKeys('motorola'); query.sendKeys('motorola');
waitForCount(phoneList, 8);
expect(phoneList.count()).toBe(8); expect(phoneList.count()).toBe(8);
}); });
@ -51,6 +60,7 @@ describe('PhoneCat Application', function() {
} }
queryField.sendKeys('tablet'); // Let's narrow the dataset to make the assertions shorter queryField.sendKeys('tablet'); // Let's narrow the dataset to make the assertions shorter
waitForCount(phoneNameColumn, 2);
expect(getNames()).toEqual([ expect(getNames()).toEqual([
'Motorola XOOM\u2122 with Wi-Fi', 'Motorola XOOM\u2122 with Wi-Fi',
@ -66,10 +76,16 @@ describe('PhoneCat Application', function() {
}); });
it('should render phone specific links', function() { it('should render phone specific links', function() {
let phoneList = element.all(by.repeater('phone in $ctrl.phones'));
let query = element(by.model('$ctrl.query')); let query = element(by.model('$ctrl.query'));
query.sendKeys('nexus');
element.all(by.css('.phones li a')).first().click(); query.sendKeys('nexus');
waitForCount(phoneList, 1);
let nexusPhone = phoneList.first();
let detailLink = nexusPhone.all(by.css('a')).first()
detailLink.click();
expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s'); expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s');
}); });

View File

@ -202,10 +202,10 @@ The following are some of the key AngularJS built-in directives and their equiva
### Bootstrapping ### Bootstrapping
<code-example hideCopy path="ajs-quick-reference/src/main.ts" title="main.ts" linenums="false"></code-example> <code-example hideCopy path="ajs-quick-reference/src/main.ts" header="main.ts" linenums="false"></code-example>
<br> <br>
<code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" title="app.module.ts" linenums="false"></code-example> <code-example hideCopy path="ajs-quick-reference/src/app/app.module.1.ts" header="app.module.ts" linenums="false"></code-example>
Angular doesn't have a bootstrap directive. Angular doesn't have a bootstrap directive.

View File

@ -37,7 +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. Import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
<code-example path="animations/src/app/app.module.1.ts" title="src/app/app.module.ts" language="typescript" linenums="false"> <code-example path="animations/src/app/app.module.1.ts" header="src/app/app.module.ts" language="typescript" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -49,7 +49,7 @@ Import `BrowserAnimationsModule`, which introduces the animation capabilities in
If you plan to use specific animation functions in component files, import those functions from `@angular/animations`. If you plan to use specific animation functions in component files, import those functions from `@angular/animations`.
<code-example path="animations/src/app/app.component.ts" title="src/app/app.component.ts" region="imports" language="typescript"> <code-example path="animations/src/app/app.component.ts" header="src/app/app.component.ts" region="imports" language="typescript">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -61,7 +61,7 @@ If you plan to use specific animation functions in component files, import those
In the component file, add a metadata property called `animations:` within the `@Component()` decorator. You put the trigger that defines an animation within the `animations` metadata property. In the component file, add a metadata property called `animations:` within the `@Component()` decorator. You put the trigger that defines an animation within the `animations` metadata property.
<code-example path="animations/src/app/app.component.ts" title="src/app/app.component.ts" region="decorator" language="typescript"> <code-example path="animations/src/app/app.component.ts" header="src/app/app.component.ts" region="decorator" language="typescript">
</code-example> </code-example>
## Animating a simple transition ## Animating a simple transition
@ -82,12 +82,12 @@ Use the `style()` function to define a set of styles to associate with a given s
Let's see how Angular's `state()` function works with the `style­()` function to set CSS style attributes. In this code snippet, multiple style attributes are set at the same time for the state. In the `open` state, the button has a height of 200 pixels, an opacity of 1, and a background color of yellow. Let's see how Angular's `state()` function works with the `style­()` function to set CSS style attributes. In this code snippet, multiple style attributes are set at the same time for the state. In the `open` state, the button has a height of 200 pixels, an opacity of 1, and a background color of yellow.
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" region="state1" language="typescript"> <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" region="state1" language="typescript">
</code-example> </code-example>
In the `closed` state, shown below, the button has a height of 100 pixels, an opacity of 0.5, and a background color of green. In the `closed` state, shown below, the button has a height of 100 pixels, an opacity of 0.5, and a background color of green.
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" region="state2" language="typescript"> <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" region="state2" language="typescript">
</code-example> </code-example>
### Transitions and timing ### Transitions and timing
@ -134,7 +134,7 @@ The third argument, `easing`, controls how the animation [accelerates and decele
This example provides a state transition from `open` to `closed` with a one second transition between states. This example provides a state transition from `open` to `closed` with a one second transition between states.
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" language="typescript" <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript"
region="transition1"> region="transition1">
</code-example> </code-example>
@ -142,7 +142,7 @@ In the code snippet above, the `=>` operator indicates unidirectional transition
This example adds a state transition from the `closed` state to the `open` state with a 0.5 second transition animation arc. This example adds a state transition from the `closed` state to the `open` state with a 0.5 second transition animation arc.
<code-example path="animations/src/app/open-close.component.ts" title="src/app/open-close.component.ts" language="typescript" <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript"
region="transition2"> region="transition2">
</code-example> </code-example>
@ -180,7 +180,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. 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" title="src/app/open-close.component.ts" language="typescript" <code-example path="animations/src/app/open-close.component.ts" header="src/app/open-close.component.ts" language="typescript"
region="component" linenums="false"> region="component" linenums="false">
</code-example> </code-example>
@ -194,7 +194,7 @@ The animation is executed or triggered when the expression value changes to a ne
The following code snippet binds the trigger to the value of the `isOpen` property. The following code snippet binds the trigger to the value of the `isOpen` property.
<code-example path="animations/src/app/open-close.component.1.html" title="src/app/open-close.component.html" <code-example path="animations/src/app/open-close.component.1.html" header="src/app/open-close.component.html"
region="compare"> region="compare">
</code-example> </code-example>
@ -216,15 +216,15 @@ Here are the code files discussed in the transition example.
<code-tabs> <code-tabs>
<code-pane title="src/app/open-close.component.ts" path="animations/src/app/open-close.component.ts" language="typescript" <code-pane header="src/app/open-close.component.ts" path="animations/src/app/open-close.component.ts" language="typescript"
region="component"> region="component">
</code-pane> </code-pane>
<code-pane title="src/app/open-close.component.html" path="animations/src/app/open-close.component.1.html" <code-pane header="src/app/open-close.component.html" path="animations/src/app/open-close.component.1.html"
region="trigger"> region="trigger">
</code-pane> </code-pane>
<code-pane title="src/app/open-close.component.css" path="animations/src/app/open-close.component.css"> <code-pane header="src/app/open-close.component.css" path="animations/src/app/open-close.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>

View File

@ -8,7 +8,7 @@ This guide explains how to specify metadata and apply available compiler options
<div class="alert is-helpful" <div class="alert is-helpful"
<a href="https://www.youtube.com/watch?v=kW9cJsvcsGo">Watch compiler author Tobias Bosch explain the Angular Compiler</a> at AngularConnect 2016. <a href="https://www.youtube.com/watch?v=kW9cJsvcsGo">Watch compiler author Tobias Bosch explain the Angular compiler</a> at AngularConnect 2016.
</div> </div>
@ -21,7 +21,7 @@ Angular offers two ways to compile your application:
1. **_Just-in-Time_ (JIT)**, which compiles your app in the browser at runtime. 1. **_Just-in-Time_ (JIT)**, which compiles your app in the browser at runtime.
1. **_Ahead-of-Time_ (AOT)**, which compiles your app at build time. 1. **_Ahead-of-Time_ (AOT)**, which compiles your app at build time.
JIT compilation is the default when you run the _build-only_ or the _build-and-serve-locally_ CLI commands: JIT compilation is the default when you run the [`ng build`](cli/build) (build only) or [`ng serve`](cli/serve) (build and serve locally) CLI commands:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng build ng build
@ -30,7 +30,7 @@ JIT compilation is the default when you run the _build-only_ or the _build-and-s
{@a compile} {@a compile}
For AOT compilation, append the `--aot` flags to the _build-only_ or the _build-and-serve-locally_ CLI commands: For AOT compilation, include the `--aot` option with the `ng build` or `ng serve` command:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng build --aot ng build --aot
@ -41,7 +41,7 @@ For AOT compilation, append the `--aot` flags to the _build-only_ or the _build-
The `ng build` command with the `--prod` meta-flag (`ng build --prod`) compiles with AOT by default. The `ng build` command with the `--prod` meta-flag (`ng build --prod`) compiles with AOT by default.
See the [CLI documentation](https://github.com/angular/angular-cli/wiki) for details, especially the [`build` topic](https://github.com/angular/angular-cli/wiki/build). See the [CLI command reference](cli) and [Building and serving Angular apps](guide/build) for more information.
</div> </div>
@ -1241,7 +1241,7 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
### Non-null type assertion operator ### Non-null type assertion operator
Use the [non-null type assertion operator](guide/template-syntax#non-null-assertion-operator) Use the [non-null type assertion operator](guide/template-syntax#non-null-assertion-operator)
to suppress the `Object is possibly 'undefined'` error when it is incovienent to use to suppress the `Object is possibly 'undefined'` error when it is inconvenient to use
`*ngIf` or when some constraint in the component ensures that the expression is always `*ngIf` or when some constraint in the component ensures that the expression is always
non-null when the binding expression is interpolated. non-null when the binding expression is interpolated.
@ -1366,7 +1366,7 @@ for example, the content of annotations (such as a component's template), which
emits to the `.js` file but not to the `.d.ts` file. emits to the `.js` file but not to the `.d.ts` file.
This option should be set to `true` if you are using TypeScript's `--outFile` option, because the metadata files This option should be set to `true` if you are using TypeScript's `--outFile` option, because the metadata files
are not valid for this style of TypeScript output. It is not recommeded to use `--outFile` with are not valid for this style of TypeScript output. It is not recommended to use `--outFile` with
Angular. Use a bundler, such as [webpack](https://webpack.js.org/), instead. Angular. Use a bundler, such as [webpack](https://webpack.js.org/), instead.
This option can also be set to `true` when using factory summaries because the factory summaries This option can also be set to `true` when using factory summaries because the factory summaries
@ -1461,7 +1461,7 @@ JavaScript with [JSDoc](http://usejsdoc.org/) comments needed by the
### *annotationsAs* ### *annotationsAs*
Use this option to modify how the Angular specific annotations are emitted to improve tree-shaking. Non-Angular Use this option to modify how the Angular specific annotations are emitted to improve tree-shaking. Non-Angular
annotations and decorators are unnaffected. Default is `static fields`. annotations and decorators are unaffected. Default is `static fields`.
<style> <style>
td, th {vertical-align: top} td, th {vertical-align: top}

View File

@ -15,7 +15,7 @@ Its `selectHero()` method sets a `selectedHero` property when the user clicks to
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 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. The service is provided to the component through the dependency injection system.
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (class)" region="class"></code-example> <code-example path="architecture/src/app/hero-list.component.ts" linenums="false" 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()`. 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`. Here's an example of basic metadata for `HeroListComponent`.
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example> <code-example path="architecture/src/app/hero-list.component.ts" linenums="false" header="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
This example shows some of the most useful `@Component` configuration options: This example shows some of the most useful `@Component` configuration options:
@ -63,7 +63,7 @@ A template looks like regular HTML, except that it also contains Angular [templa
For example, here is a template for the Tutorial's `HeroListComponent`. For example, here is a template for the Tutorial's `HeroListComponent`.
<code-example path="architecture/src/app/hero-list.component.html" title="src/app/hero-list.component.html"></code-example> <code-example path="architecture/src/app/hero-list.component.html" header="src/app/hero-list.component.html"></code-example>
This template uses typical HTML elements like `<h2>` and `<p>`, and also includes Angular template-syntax elements, `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and `<app-hero-detail>`. The template-syntax elements tell Angular how to render the HTML to the screen, using program logic and data. This template uses typical HTML elements like `<h2>` and `<p>`, and also includes Angular template-syntax elements, `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and `<app-hero-detail>`. The template-syntax elements tell Angular how to render the HTML to the screen, using program logic and data.
@ -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. This example from the `HeroListComponent` template uses three of these forms.
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" title="src/app/hero-list.component.html (binding)" region="binding"></code-example> <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>
* The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation) * The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation)
displays the component's `hero.name` property value within the `<li>` element. displays the component's `hero.name` property value within the `<li>` element.
@ -101,7 +101,7 @@ Two-way data binding (used mainly in [template-driven forms](guide/forms))
combines property and event binding in a single notation. 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. Here's an example from the `HeroDetailComponent` template that uses two-way data binding with the `ngModel` directive.
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example> <code-example path="architecture/src/app/hero-detail.component.html" linenums="false" 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. 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, The user's changes also flow back to the component, resetting the property to the latest value,
@ -164,7 +164,7 @@ Just as for components, the metadata for a directive associates the decorated cl
*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. The example template uses two built-in structural directives to add application logic to how the view is rendered.
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" title="src/app/hero-list.component.html (structural)" region="structural"></code-example> <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>
* [`*ngFor`](guide/displaying-data#ngFor) is an iterative; it tells Angular to stamp out one `<li>` per hero in the `heroes` list. * [`*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. * [`*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. 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" title="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example> <code-example path="architecture/src/app/hero-detail.component.html" linenums="false" header="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
Angular has more pre-defined directives that either alter the layout structure Angular has more pre-defined directives that either alter the layout structure
(for example, [ngSwitch](guide/template-syntax#ngSwitch)) (for example, [ngSwitch](guide/template-syntax#ngSwitch))

View File

@ -23,7 +23,7 @@ An NgModule is defined by a class decorated with `@NgModule()`. The `@NgModule()
Here's a simple root NgModule definition. Here's a simple root NgModule definition.
<code-example path="architecture/src/app/mini-app.ts" region="module" title="src/app/app.module.ts" linenums="false"></code-example> <code-example path="architecture/src/app/mini-app.ts" region="module" header="src/app/app.module.ts" linenums="false"></code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">

View File

@ -4,20 +4,20 @@ After you understand the basic Angular building blocks, you can begin to learn m
about the features and tools that are available to help you develop and deliver Angular applications. about the features and tools that are available to help you develop and deliver Angular applications.
Here are some key features. Here are some key features.
## Responsive programming tools ## Responsive programming
* [Lifecycle hooks](guide/lifecycle-hooks): Tap into key moments in the lifetime of a component, from its creation to its destruction, by implementing the lifecycle hook interfaces. * [Lifecycle hooks](guide/lifecycle-hooks): Tap into key moments in the lifetime of a component, from its creation to its destruction, by implementing the lifecycle hook interfaces.
* [Observables and event processing](guide/observables): How to use observables with components and services to publish and subscribe to messages of any type, such as user-interaction events and asynchronous operation results. * [Observables and event processing](guide/observables): How to use observables with components and services to publish and subscribe to messages of any type, such as user-interaction events and asynchronous operation results.
## Client-server interaction tools ## Client-server interaction
* [HTTP](guide/http): Communicate with a server to get data, save data, and invoke server-side actions with an HTTP client. * [HTTP](guide/http): Communicate with a server to get data, save data, and invoke server-side actions with an HTTP client.
* [Server-side Rendering](guide/universal): Angular Universal generates static application pages on the server through server-side rendering (SSR). This allows you to run your Angular app on the server in order to improve performance and show the first page quickly on mobile and low-powered devices, and also facilitate web crawlers. * [Server-side Rendering](guide/universal): Angular Universal generates static application pages on the server through server-side rendering (SSR). This allows you to run your Angular app on the server in order to improve performance and show the first page quickly on mobile and low-powered devices, and also facilitate web crawlers.
* [Service Workers](guide/service-worker-intro): Use a service worker to reduce dependency on the network * [Service Workers](guide/service-worker-intro): Use a service worker to reduce dependency on the network
significantly improving the use experience. significantly improving the user experience.
## Domain-specific libraries ## Domain-specific libraries
@ -28,23 +28,28 @@ without deep knowledge of animation techniques or CSS.
## Support for the development cycle ## Support for the development cycle
* [Compilation](guide/aot-compiler): Angular provides just-in-time (JIT) compilation for the development environment, and ahead-of-time (AOT) compilation for the production environment.
* [Testing platform](guide/testing): Run unit tests on your application parts as they interact with the Angular framework. * [Testing platform](guide/testing): Run unit tests on your application parts as they interact with the Angular framework.
* [Internationalization](guide/i18n): Make your app available in multiple languages with Angular's internationalization (i18n) tools. * [Internationalization](guide/i18n): Make your app available in multiple languages with Angular's internationalization (i18n) tools.
* [Compilation](guide/aot-compiler): Angular provides just-in-time (JIT) compilation for the development environment, and ahead-of-time (AOT) compilation for the production environment.
* [Security guidelines](guide/security): Learn about Angular's built-in protections against common web-app vulnerabilities and attacks such as cross-site scripting attacks. * [Security guidelines](guide/security): Learn about Angular's built-in protections against common web-app vulnerabilities and attacks such as cross-site scripting attacks.
## Setup and deployment tools ## Setup, build, and deployment configuration
* [Setup for local development](guide/setup): Set up a new project for development with QuickStart. * [CLI Command Reference](cli): The Angular CLI is a command-line tool that you use to create projects, generate application and library code, and perform a variety of ongoing development tasks such as testing, bundling, and deployment.
* [Installation](guide/npm-packages): The [Angular CLI](https://cli.angular.io/), Angular applications, and Angular itself depend on features and functionality provided by libraries that are available as [npm](https://docs.npmjs.com/) packages. * [Workspace and File Structure](guide/file-structure): Understand the structure of Angular workspace and project folders.
* [npm Packages](guide/npm-packages): The Angular Framework, Angular CLI, and components used by Angular applications are packaged as [npm](https://docs.npmjs.com/) packages and distributed via the npm registry. The Angular CLI creates a default `package.json` file, which specifies a starter set of packages that work well together and jointly support many common application scenarios.
* [TypeScript configuration](guide/typescript-configuration): TypeScript is the primary language for Angular application development. * [TypeScript configuration](guide/typescript-configuration): TypeScript is the primary language for Angular application development.
* [Browser support](guide/browser-support): Make your apps compatible across a wide range of browsers. * [Browser support](guide/browser-support): Make your apps compatible across a wide range of browsers.
* [Building and Serving](guide/build): Learn to define different build and proxy server configurations for your project, such as development, staging, and production.
* [Deployment](guide/deployment): Learn techniques for deploying your Angular application to a remote server. * [Deployment](guide/deployment): Learn techniques for deploying your Angular application to a remote server.

View File

@ -28,11 +28,11 @@ available to components through *dependency injection*.
Here's an example of a service class that logs to the browser console. Here's an example of a service class that logs to the browser console.
<code-example path="architecture/src/app/logger.service.ts" linenums="false" title="src/app/logger.service.ts (class)" region="class"></code-example> <code-example path="architecture/src/app/logger.service.ts" linenums="false" 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. Services can depend on other services. For example, here's a `HeroService` that depends on the `Logger` service, and also uses `BackendService` to get heroes. That service in turn might depend on the `HttpClient` service to fetch heroes asynchronously from a server.
<code-example path="architecture/src/app/hero.service.ts" linenums="false" title="src/app/hero.service.ts (class)" region="class"></code-example> <code-example path="architecture/src/app/hero.service.ts" linenums="false" header="src/app/hero.service.ts (class)" region="class"></code-example>
## Dependency injection (DI) ## Dependency injection (DI)
@ -62,7 +62,7 @@ A dependency doesn't have to be a service&mdash;it could be a function, for exam
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`. 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" title="src/app/hero-list.component.ts (constructor)" region="ctor"></code-example> <code-example path="architecture/src/app/hero-list.component.ts" linenums="false" 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. 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.
@ -82,7 +82,7 @@ or you can register providers with specific modules or components.
You register providers in the metadata of the service (in the `@Injectable()` decorator), 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` 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. * 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({ @Injectable({
@ -111,6 +111,6 @@ or in the `@NgModule()` or `@Component()` metadata
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. At the component level, register a service provider in the `providers` property of the `@Component()` metadata.
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (component providers)" region="providers"></code-example> <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>
For more detailed information, see the [Dependency Injection](guide/dependency-injection) section. For more detailed information, see the [Dependency Injection](guide/dependency-injection) section.

View File

@ -15,7 +15,7 @@ There are three kinds of directives in Angular:
1. Attribute directives&mdash;change the appearance or behavior of an element, component, or another directive. 1. Attribute directives&mdash;change the appearance or behavior of an element, component, or another directive.
*Components* are the most common of the three directives. *Components* are the most common of the three directives.
You saw a component for the first time in the [QuickStart](guide/quickstart) guide. You saw a component for the first time in the [Getting Started](guide/quickstart).
*Structural Directives* change the structure of the view. *Structural Directives* change the structure of the view.
Two examples are [NgFor](guide/template-syntax#ngFor) and [NgIf](guide/template-syntax#ngIf). Two examples are [NgFor](guide/template-syntax#ngFor) and [NgIf](guide/template-syntax#ngIf).
@ -37,13 +37,13 @@ This page demonstrates building a simple _appHighlight_ attribute
directive to set an element's background color directive to set an element's background color
when the user hovers over that element. You can apply it like this: 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" title="src/app/app.component.html (applied)" region="applied"></code-example> <code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" header="src/app/app.component.html (applied)" region="applied"></code-example>
{@a write-directive} {@a write-directive}
### Write the directive code ### Write the directive code
Create the directive class file in a terminal window with this CLI command. Create the directive class file in a terminal window with the CLI command [`ng generate directive`](cli/generate).
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate directive highlight ng generate directive highlight
@ -59,9 +59,9 @@ _Directives_ must be declared in [Angular Modules](guide/ngmodules) in the same
The generated `src/app/highlight.directive.ts` is as follows: The generated `src/app/highlight.directive.ts` is as follows:
<code-example path="attribute-directives/src/app/highlight.directive.0.ts" title="src/app/highlight.directive.ts"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.0.ts" header="src/app/highlight.directive.ts"></code-example>
The imported `Directive` symbol provides the Angular the `@Directive` decorator. The imported `Directive` symbol provides Angular the `@Directive` decorator.
The `@Directive` decorator's lone configuration property specifies the directive's The `@Directive` decorator's lone configuration property specifies the directive's
[CSS attribute selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors), `[appHighlight]`. [CSS attribute selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors), `[appHighlight]`.
@ -92,7 +92,7 @@ Exporting `HighlightDirective` makes the directive accessible.
Now edit the generated `src/app/highlight.directive.ts` to look as follows: Now edit the generated `src/app/highlight.directive.ts` to look as follows:
<code-example path="attribute-directives/src/app/highlight.directive.1.ts" title="src/app/highlight.directive.ts"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.1.ts" header="src/app/highlight.directive.ts"></code-example>
The `import` statement specifies an additional `ElementRef` symbol from the Angular `core` library: The `import` statement specifies an additional `ElementRef` symbol from the Angular `core` library:
@ -111,7 +111,7 @@ This first implementation sets the background color of the host element to yello
To use the new `HighlightDirective`, add a paragraph (`<p>`) element to the template of the root `AppComponent` and apply the directive as an attribute. To use the new `HighlightDirective`, add a paragraph (`<p>`) element to the template of the root `AppComponent` and apply the directive as an attribute.
<code-example path="attribute-directives/src/app/app.component.1.html" title="src/app/app.component.html" region="applied"></code-example> <code-example path="attribute-directives/src/app/app.component.1.html" header="src/app/app.component.html" region="applied"></code-example>
Now run the application to see the `HighlightDirective` in action. Now run the application to see the `HighlightDirective` in action.
@ -136,12 +136,12 @@ and respond by setting or clearing the highlight color.
Begin by adding `HostListener` to the list of imported symbols. Begin by adding `HostListener` to the list of imported symbols.
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (imports)" region="imports"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
Then add two eventhandlers that respond when the mouse enters or leaves, Then add two eventhandlers that respond when the mouse enters or leaves,
each adorned by the `HostListener` decorator. each adorned by the `HostListener` decorator.
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (mouse-methods)" region="mouse-methods"></code-example> <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>
The `@HostListener` decorator lets you subscribe to events of the DOM The `@HostListener` decorator lets you subscribe to events of the DOM
element that hosts an attribute directive, the `<p>` in this case. element that hosts an attribute directive, the `<p>` in this case.
@ -162,11 +162,11 @@ 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 helper method, `highlight`, was extracted from the constructor.
The revised constructor simply declares the injected `el: ElementRef`. The revised constructor simply declares the injected `el: ElementRef`.
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (constructor)" region="ctor"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (constructor)" region="ctor"></code-example>
Here's the updated directive in full: Here's the updated directive in full:
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" title="src/app/highlight.directive.ts"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.2.ts" header="src/app/highlight.directive.ts"></code-example>
Run the app and confirm that the background color appears when Run the app and confirm that the background color appears when
the mouse hovers over the `p` and disappears as it moves out. the mouse hovers over the `p` and disappears as it moves out.
@ -183,11 +183,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. 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`. 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" title="src/app/highlight.directive.ts (imports)" region="imports"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" header="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
Add a `highlightColor` property to the directive class like this: Add a `highlightColor` property to the directive class like this:
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (highlightColor)" region="color"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (highlightColor)" region="color"></code-example>
{@a input} {@a input}
@ -200,19 +200,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: 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" title="src/app/app.component.html (excerpt)" region="color-1"></code-example> <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>
Add a `color` property to the `AppComponent`. Add a `color` property to the `AppComponent`.
<code-example path="attribute-directives/src/app/app.component.1.ts" linenums="false" title="src/app/app.component.ts (class)" region="class"></code-example> <code-example path="attribute-directives/src/app/app.component.1.ts" linenums="false" header="src/app/app.component.ts (class)" region="class"></code-example>
Let it control the highlight color with a property binding. Let it control the highlight color with a property binding.
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" title="src/app/app.component.html (excerpt)" region="color-2"></code-example> <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>
That's good, but it would be nice to _simultaneously_ apply the directive and set the color _in the same attribute_ like this. 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" title="src/app/app.component.html (color)" region="color"></code-example> <code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (color)" region="color"></code-example>
The `[appHighlight]` attribute binding both applies the highlighting directive to the `<p>` element The `[appHighlight]` attribute binding both applies the highlighting directive to the `<p>` element
and sets the directive's highlight color with a property binding. and sets the directive's highlight color with a property binding.
@ -221,7 +221,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. 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" title="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" linenums="false" 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. This is disagreeable. The word, `appHighlight`, is a terrible property name and it doesn't convey the property's intent.
@ -233,23 +233,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`. 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" title="src/app/highlight.directive.ts (color property with alias)" region="color"></code-example> <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>
_Inside_ the directive the property is known as `highlightColor`. _Inside_ the directive the property is known as `highlightColor`.
_Outside_ the directive, where you bind to it, it's known as `appHighlight`. _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: 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" title="src/app/app.component.html (color)" region="color"></code-example> <code-example path="attribute-directives/src/app/app.component.html" linenums="false" 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. 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: 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" title="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter"></code-example> <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>
Here's the latest version of the directive class. Here's the latest version of the directive class.
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" title="src/app/highlight.directive.ts (excerpt)"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" header="src/app/highlight.directive.ts (excerpt)"></code-example>
## Write a harness to try it ## Write a harness to try it
@ -259,11 +259,11 @@ lets you pick the highlight color with a radio button and bind your color choice
Update <code>app.component.html</code> as follows: Update <code>app.component.html</code> as follows:
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (v2)" region="v2"></code-example> <code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (v2)" region="v2"></code-example>
Revise the `AppComponent.color` so that it has no initial value. Revise the `AppComponent.color` so that it has no initial value.
<code-example path="attribute-directives/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts (class)" region="class"></code-example> <code-example path="attribute-directives/src/app/app.component.ts" linenums="false" header="src/app/app.component.ts (class)" region="class"></code-example>
Here are the harness and directive in action. Here are the harness and directive in action.
@ -283,12 +283,12 @@ Let the template developer set the default color.
Add a second **input** property to `HighlightDirective` called `defaultColor`: Add a second **input** property to `HighlightDirective` called `defaultColor`:
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (defaultColor)" region="defaultColor"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" 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`, 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. 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" title="src/app/highlight.directive.ts (mouse-enter)" region="mouse-enter"></code-example> <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>
How do you bind to a second property when you're already binding to the `appHighlight` attribute name? How do you bind to a second property when you're already binding to the `appHighlight` attribute name?
@ -296,7 +296,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` 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. and fall back to "violet" as the default color.
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (defaultColor)" region="defaultColor"></code-example> <code-example path="attribute-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (defaultColor)" region="defaultColor"></code-example>
Angular knows that the `defaultColor` binding belongs to the `HighlightDirective` Angular knows that the `defaultColor` binding belongs to the `HighlightDirective`
because you made it _public_ with the `@Input` decorator. because you made it _public_ with the `@Input` decorator.
@ -319,12 +319,12 @@ This page covered how to:
The final source code follows: The final source code follows:
<code-tabs> <code-tabs>
<code-pane title="app/app.component.ts" path="attribute-directives/src/app/app.component.ts"></code-pane> <code-pane header="app/app.component.ts" path="attribute-directives/src/app/app.component.ts"></code-pane>
<code-pane title="app/app.component.html" path="attribute-directives/src/app/app.component.html"></code-pane> <code-pane header="app/app.component.html" path="attribute-directives/src/app/app.component.html"></code-pane>
<code-pane title="app/highlight.directive.ts" path="attribute-directives/src/app/highlight.directive.ts"></code-pane> <code-pane header="app/highlight.directive.ts" path="attribute-directives/src/app/highlight.directive.ts"></code-pane>
<code-pane title="app/app.module.ts" path="attribute-directives/src/app/app.module.ts"></code-pane> <code-pane header="app/app.module.ts" path="attribute-directives/src/app/app.module.ts"></code-pane>
<code-pane title="main.ts" path="attribute-directives/src/main.ts"></code-pane> <code-pane header="main.ts" path="attribute-directives/src/main.ts"></code-pane>
<code-pane title="index.html" path="attribute-directives/src/index.html"></code-pane> <code-pane header="index.html" path="attribute-directives/src/index.html"></code-pane>
</code-tabs> </code-tabs>
@ -338,11 +338,11 @@ You can also experience and download the <live-example title="Attribute Directiv
In this demo, the `highlightColor` property is an ***input*** property of In this demo, the `highlightColor` property is an ***input*** property of
the `HighlightDirective`. You've seen it applied without an alias: the `HighlightDirective`. You've seen it applied without an alias:
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (color)" region="color"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
You've seen it with an alias: You've seen it with an alias:
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (color)" region="color"></code-example> <code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" header="src/app/highlight.directive.ts (color)" region="color"></code-example>
Either way, the `@Input` decorator tells Angular that this property is Either way, the `@Input` decorator tells Angular that this property is
_public_ and available for binding by a parent component. _public_ and available for binding by a parent component.
@ -374,7 +374,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: Now apply that reasoning to the following example:
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (color)" region="color"></code-example> <code-example path="attribute-directives/src/app/app.component.html" linenums="false" 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 `color` property in the expression on the right belongs to the template's component.
The template and its component trust each other. The template and its component trust each other.

View File

@ -12,7 +12,7 @@ Every application has at least one Angular module, the _root_ module
that you bootstrap to launch the application. that you bootstrap to launch the application.
By convention, it is usually called `AppModule`. By convention, it is usually called `AppModule`.
If you use the CLI to generate an app, the default `AppModule` is as follows: If you use the [Angular CLI](cli) to generate an app, the default `AppModule` is as follows:
```typescript ```typescript
/* JavaScript imports */ /* JavaScript imports */
@ -52,7 +52,7 @@ The `@NgModule` decorator identifies `AppModule` as an `NgModule` class.
* **_bootstrap_**&mdash;the _root_ component that Angular creates and inserts * **_bootstrap_**&mdash;the _root_ component that Angular creates and inserts
into the `index.html` host web page. into the `index.html` host web page.
The default CLI application only has one component, `AppComponent`, so it The default application created by the Angular CLI only has one component, `AppComponent`, so it
is in both the `declarations` and the `bootstrap` arrays. is in both the `declarations` and the `bootstrap` arrays.
{@a declarations} {@a declarations}
@ -106,18 +106,18 @@ 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. Those three steps look like the following. In the file where you create your directive, export it.
The following example, named `ItemDirective` is the default directive structure that the CLI generates in its own file, `item.directive.ts`: The following example, named `ItemDirective` is the default directive structure that the CLI generates in its own file, `item.directive.ts`:
<code-example path="bootstrapping/src/app/item.directive.ts" region="directive" title="src/app/item.directive.ts" linenums="false"> <code-example path="bootstrapping/src/app/item.directive.ts" region="directive" header="src/app/item.directive.ts" linenums="false">
</code-example> </code-example>
The key point here is that you have to export it so you can import it elsewhere. Next, import it The key point here is that you have to export it so you can import it elsewhere. Next, import it
into the NgModule, in this example `app.module.ts`, with a JavaScript import statement: into the NgModule, in this example `app.module.ts`, with a JavaScript import statement:
<code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" title="src/app/app.module.ts" linenums="false"> <code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
And in the same file, add it to the `@NgModule` `declarations` array: And in the same file, add it to the `@NgModule` `declarations` array:
<code-example path="bootstrapping/src/app/app.module.ts" region="declarations" title="src/app/app.module.ts" linenums="false"> <code-example path="bootstrapping/src/app/app.module.ts" region="declarations" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>

View File

@ -122,7 +122,7 @@ Note that polyfills cannot magically transform an old, slow browser into a moder
## Enabling polyfills ## Enabling polyfills
[Angular CLI](https://github.com/angular/angular-cli/wiki) users enable polyfills through the `src/polyfills.ts` file that [Angular CLI](cli) users enable polyfills through the `src/polyfills.ts` file that
the CLI created with your project. the CLI created with your project.
This file incorporates the mandatory and many of the optional polyfills as JavaScript `import` statements. This file incorporates the mandatory and many of the optional polyfills as JavaScript `import` statements.
@ -140,7 +140,7 @@ For example, [if you need the web animations polyfill](http://caniuse.com/#feat=
Then open the `polyfills.ts` file and un-comment the corresponding `import` statement as in the following example: Then open the `polyfills.ts` file and un-comment the corresponding `import` statement as in the following example:
<code-example title="src/polyfills.ts"> <code-example header="src/polyfills.ts">
/** /**
* Required to support Web Animations `@angular/platform-browser/animations`. * Required to support Web Animations `@angular/platform-browser/animations`.
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
@ -553,7 +553,7 @@ computed with the <a href="http://closure-compiler.appspot.com/home">closure com
If you are not using the CLI, you should add your polyfill scripts directly to the host web page (`index.html`), perhaps like this. If you are not using the CLI, you should add your polyfill scripts directly to the host web page (`index.html`), perhaps like this.
<code-example title="src/index.html"> <code-example header="src/index.html">
&lt;!-- pre-zone polyfills --> &lt;!-- pre-zone polyfills -->
&lt;script src="node_modules/core-js/client/shim.min.js">&lt;/script> &lt;script src="node_modules/core-js/client/shim.min.js">&lt;/script>
&lt;script src="node_modules/web-animations-js/web-animations.min.js">&lt;/script> &lt;script src="node_modules/web-animations-js/web-animations.min.js">&lt;/script>

View File

@ -1,6 +1,6 @@
# Building and serving Angular apps # Building and serving Angular apps
*intro - here are some topics of interest in the app development cycle* This page discusses build-specific configuration options for Angular projects.
{@a app-environments} {@a app-environments}
@ -8,7 +8,7 @@
You can define different named build configurations for your project, such as *stage* and *production*, with different defaults. You can define different named build configurations for your project, such as *stage* and *production*, with different defaults.
Each named build configuration can have defaults for any of the options that apply to the various build targets, such as `build`, `serve`, and `test`. The CLI `build`, `serve`, and `test` commands can then replace files with appropriate versions for your intended target environment. Each named build configuration can have defaults for any of the options that apply to the various build targets, such as `build`, `serve`, and `test`. The [Angular CLI](cli) `build`, `serve`, and `test` commands can then replace files with appropriate versions for your intended target environment.
The following figure shows how a project has multiple build targets, which can be executed using the named configurations that you define. The following figure shows how a project has multiple build targets, which can be executed using the named configurations that you define.
@ -260,50 +260,6 @@ Each budget entry is a JSON object with the following properties:
</table> </table>
{@a assets}
## Adding project assets
You can configure your project with a set of assets, such as images, to copy directly into the build for a particular build target.
Each build target section of the CLI configuration file, `angular.json`, has an `assets` section that lists files or folders you want to copy into the build for that target.
By default, the `src/assets/` folder and `src/favicon.ico` are copied into a build.
```
"assets": [
"src/assets",
"src/favicon.ico"
]
```
You can edit the assets configuration to extend it for assets outside your project.
For example, the following invokes the [node-glob pattern matcher](https://github.com/isaacs/node-glob) using input from a given base folder.
It sends output to a folder that is relative to `outDir`, a configuration value that defaults to `dist/`*project-name*).
The result in this cased is the same as for the default assets configuration.
```
"assets": [
{ "glob": "**/*", "input": "src/assets/", "output": "/assets/" },
{ "glob": "favicon.ico", "input": "/src", "output": "/" },
]
```
You can use this extended configuration to copy assets from outside your project.
For instance, you can copy assets from a node package with the following value:
```
"assets": [
{ "glob": "**/*", "input": "./node_modules/some-package/images", "output": "/some-package/" },
]
```
This makes the contents of `node_modules/some-package/images/` available in the output folder `dist/some-package/`.
<div class="alert is-critical">
For reasons of security, the CLI never writes files outside of the project output path.
</div>
{@a browser-compat} {@a browser-compat}
@ -312,7 +268,7 @@ This makes the contents of `node_modules/some-package/images/` available in the
The CLI uses [Autoprefixer](https://github.com/postcss/autoprefixer) to ensure compatibility with different browser and browser versions. The CLI uses [Autoprefixer](https://github.com/postcss/autoprefixer) to ensure compatibility with different browser and browser versions.
You may find it necessary to target specific browsers or exclude certain browser versions from your build. You may find it necessary to target specific browsers or exclude certain browser versions from your build.
Internally, Autoprefixer relies on a library called [Browserslist(https://github.com/ai/browserslist)] to figure out which browsers to support with prefixing. Internally, Autoprefixer relies on a library called [Browserslist](https://github.com/browserslist/browserslist) to figure out which browsers to support with prefixing.
Browserlist looks for configuration options in a `browserlist` property of the package configuration file, or in a configuration file named `.browserslistrc`. Browserlist looks for configuration options in a `browserlist` property of the package configuration file, or in a configuration file named `.browserslistrc`.
Autoprefixer looks for the Browserlist configuration when it prefixes your CSS. Autoprefixer looks for the Browserlist configuration when it prefixes your CSS.
@ -331,9 +287,9 @@ Autoprefixer looks for the Browserlist configuration when it prefixes your CSS.
last 2 versions last 2 versions
``` ```
See the [browserslist repo](https://github.com/ai/browserslist) for more examples of how to target specific browsers and versions. See the [browserslist repo](https://github.com/browserslist/browserslist) for more examples of how to target specific browsers and versions.
<div class="alert is-helpful">> <div class="alert is-helpful">
Backward compatibility Backward compatibility
If you want to produce a progressive web app and are using [Lighthouse](https://developers.google.com/web/tools/lighthouse/) to grade the project, add the following browserslist entry to your `package.json` file, in order to eliminate the [old flexbox](https://developers.google.com/web/tools/lighthouse/audits/old-flexbox) prefixes: If you want to produce a progressive web app and are using [Lighthouse](https://developers.google.com/web/tools/lighthouse/) to grade the project, add the following browserslist entry to your `package.json` file, in order to eliminate the [old flexbox](https://developers.google.com/web/tools/lighthouse/audits/old-flexbox) prefixes:
@ -353,7 +309,7 @@ If you want to produce a progressive web app and are using [Lighthouse](https://
## Proxying to a backend server ## Proxying to a backend server
You can use the [proxying support](https://webpack.js.org/configuration/dev-server/#devserver-proxy) in the `webpack` dev server to divert certain URLs to a backend server, by passing a file to the `--proxy-config` build option. You can use the [proxying support](https://webpack.js.org/configuration/dev-server/#devserver-proxy) in the `webpack` dev server to divert certain URLs to a backend server, by passing a file to the `--proxy-config` build option.
For example, to divert all calls for http://localhost:4200/api to a server running on http://localhost:3000/api, take the following steps. For example, to divert all calls for `http://localhost:4200/api` to a server running on `http://localhost:3000/api`, take the following steps.
1. Create a file `proxy.conf.json` in the projects `src/` folder, next to `package.json`. 1. Create a file `proxy.conf.json` in the projects `src/` folder, next to `package.json`.

View File

@ -19,7 +19,7 @@ Observables are often compared to promises. Here are some key differences:
### Creation and subscription ### Creation and subscription
* Observables are not executed until a consumer subcribes. The `subscribe()` executes the defined behavior once, and it can be called again. Each subscription has its own computation. Resubscription causes recomputation of values. * Observables are not executed until a consumer subscribes. The `subscribe()` executes the defined behavior once, and it can be called again. Each subscription has its own computation. Resubscription causes recomputation of values.
<code-example hideCopy> <code-example hideCopy>
// declare a publishing operation // declare a publishing operation

View File

@ -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. * 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" title="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" linenums="false"></code-example>
## Parallel animation using group() function ## 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. 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" title="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" linenums="false"></code-example>
## Sequential vs. parallel animations ## Sequential vs. parallel animations
@ -70,11 +70,11 @@ The filter works in real time as you type. Elements leave the page as you type e
The HTML template contains a trigger called `filterAnimation`. The HTML template contains a trigger called `filterAnimation`.
<code-example path="animations/src/app/hero-list-page.component.html" title="src/app/hero-list-page.component.html" region="filter-animations"></code-example> <code-example path="animations/src/app/hero-list-page.component.html" header="src/app/hero-list-page.component.html" region="filter-animations"></code-example>
The component file contains three transitions. The component file contains three transitions.
<code-example path="animations/src/app/hero-list-page.component.ts" title="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" linenums="false"></code-example>
The animation does the following: The animation does the following:

View File

@ -28,7 +28,7 @@ in which two or more components share information.
typically adorned with [@Input decorations](guide/template-syntax#inputs-outputs). typically adorned with [@Input decorations](guide/template-syntax#inputs-outputs).
<code-example path="component-interaction/src/app/hero-child.component.ts" title="component-interaction/src/app/hero-child.component.ts"> <code-example path="component-interaction/src/app/hero-child.component.ts" header="component-interaction/src/app/hero-child.component.ts">
</code-example> </code-example>
@ -41,7 +41,7 @@ binding its `master` string property to the child's `master` alias,
and each iteration's `hero` instance to the child's `hero` property. and each iteration's `hero` instance to the child's `hero` property.
<code-example path="component-interaction/src/app/hero-parent.component.ts" title="component-interaction/src/app/hero-parent.component.ts"> <code-example path="component-interaction/src/app/hero-parent.component.ts" header="component-interaction/src/app/hero-parent.component.ts">
</code-example> </code-example>
@ -61,7 +61,7 @@ The running application displays three heroes:
E2E test that all children were instantiated and displayed as expected: E2E test that all children were instantiated and displayed as expected:
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child" title="component-interaction/e2e/src/app.e2e-spec.ts"> <code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child" header="component-interaction/e2e/src/app.e2e-spec.ts">
</code-example> </code-example>
@ -79,7 +79,7 @@ The setter of the `name` input property in the child `NameChildComponent`
trims the whitespace from a name and replaces an empty value with default text. trims the whitespace from a name and replaces an empty value with default text.
<code-example path="component-interaction/src/app/name-child.component.ts" title="component-interaction/src/app/name-child.component.ts"> <code-example path="component-interaction/src/app/name-child.component.ts" header="component-interaction/src/app/name-child.component.ts">
</code-example> </code-example>
@ -88,7 +88,7 @@ trims the whitespace from a name and replaces an empty value with default text.
Here's the `NameParentComponent` demonstrating name variations including a name with all spaces: Here's the `NameParentComponent` demonstrating name variations including a name with all spaces:
<code-example path="component-interaction/src/app/name-parent.component.ts" title="component-interaction/src/app/name-parent.component.ts"> <code-example path="component-interaction/src/app/name-parent.component.ts" header="component-interaction/src/app/name-parent.component.ts">
</code-example> </code-example>
@ -105,7 +105,7 @@ Here's the `NameParentComponent` demonstrating name variations including a name
E2E tests of input property setter with empty and non-empty names: E2E tests of input property setter with empty and non-empty names:
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child-setter" title="component-interaction/e2e/src/app.e2e-spec.ts"> <code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child-setter" header="component-interaction/e2e/src/app.e2e-spec.ts">
</code-example> </code-example>
@ -134,7 +134,7 @@ Learn about `ngOnChanges()` in the [LifeCycle Hooks](guide/lifecycle-hooks) chap
This `VersionChildComponent` detects changes to the `major` and `minor` input properties and composes a log message reporting these changes: This `VersionChildComponent` detects changes to the `major` and `minor` input properties and composes a log message reporting these changes:
<code-example path="component-interaction/src/app/version-child.component.ts" title="component-interaction/src/app/version-child.component.ts"> <code-example path="component-interaction/src/app/version-child.component.ts" header="component-interaction/src/app/version-child.component.ts">
</code-example> </code-example>
@ -143,7 +143,7 @@ This `VersionChildComponent` detects changes to the `major` and `minor` input pr
The `VersionParentComponent` supplies the `minor` and `major` values and binds buttons to methods that change them. The `VersionParentComponent` supplies the `minor` and `major` values and binds buttons to methods that change them.
<code-example path="component-interaction/src/app/version-parent.component.ts" title="component-interaction/src/app/version-parent.component.ts"> <code-example path="component-interaction/src/app/version-parent.component.ts" header="component-interaction/src/app/version-parent.component.ts">
</code-example> </code-example>
@ -164,7 +164,7 @@ Test that ***both*** input properties are set initially and that button clicks t
the expected `ngOnChanges` calls and values: the expected `ngOnChanges` calls and values:
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child-onchanges" title="component-interaction/e2e/src/app.e2e-spec.ts"> <code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="parent-to-child-onchanges" header="component-interaction/e2e/src/app.e2e-spec.ts">
</code-example> </code-example>
@ -184,7 +184,7 @@ The child's `EventEmitter` property is an ***output property***,
as seen in this `VoterComponent`: as seen in this `VoterComponent`:
<code-example path="component-interaction/src/app/voter.component.ts" title="component-interaction/src/app/voter.component.ts"> <code-example path="component-interaction/src/app/voter.component.ts" header="component-interaction/src/app/voter.component.ts">
</code-example> </code-example>
@ -196,7 +196,7 @@ The parent `VoteTakerComponent` binds an event handler called `onVoted()` that r
payload `$event` and updates a counter. payload `$event` and updates a counter.
<code-example path="component-interaction/src/app/votetaker.component.ts" title="component-interaction/src/app/votetaker.component.ts"> <code-example path="component-interaction/src/app/votetaker.component.ts" header="component-interaction/src/app/votetaker.component.ts">
</code-example> </code-example>
@ -217,7 +217,7 @@ and the method processes it:
Test that clicking the *Agree* and *Disagree* buttons update the appropriate counters: Test that clicking the *Agree* and *Disagree* buttons update the appropriate counters:
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="child-to-parent" title="component-interaction/e2e/src/app.e2e-spec.ts"> <code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="child-to-parent" header="component-interaction/e2e/src/app.e2e-spec.ts">
</code-example> </code-example>
@ -240,7 +240,7 @@ The following is a child `CountdownTimerComponent` that repeatedly counts down t
It has `start` and `stop` methods that control the clock and it displays a It has `start` and `stop` methods that control the clock and it displays a
countdown status message in its own template. countdown status message in its own template.
<code-example path="component-interaction/src/app/countdown-timer.component.ts" title="component-interaction/src/app/countdown-timer.component.ts"> <code-example path="component-interaction/src/app/countdown-timer.component.ts" header="component-interaction/src/app/countdown-timer.component.ts">
</code-example> </code-example>
@ -249,7 +249,7 @@ countdown status message in its own template.
The `CountdownLocalVarParentComponent` that hosts the timer component is as follows: The `CountdownLocalVarParentComponent` that hosts the timer component is as follows:
<code-example path="component-interaction/src/app/countdown-parent.component.ts" region="lv" title="component-interaction/src/app/countdown-parent.component.ts"> <code-example path="component-interaction/src/app/countdown-parent.component.ts" region="lv" header="component-interaction/src/app/countdown-parent.component.ts">
</code-example> </code-example>
@ -284,7 +284,7 @@ match the seconds displayed in the child's status message.
Test also that clicking the *Stop* button pauses the countdown timer: Test also that clicking the *Stop* button pauses the countdown timer:
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="countdown-timer-tests" title="component-interaction/e2e/src/app.e2e-spec.ts"> <code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="countdown-timer-tests" header="component-interaction/e2e/src/app.e2e-spec.ts">
</code-example> </code-example>
@ -324,7 +324,7 @@ is solely for the purpose of demonstration.
Here is the parent, `CountdownViewChildParentComponent`: Here is the parent, `CountdownViewChildParentComponent`:
<code-example path="component-interaction/src/app/countdown-parent.component.ts" region="vc" title="component-interaction/src/app/countdown-parent.component.ts"> <code-example path="component-interaction/src/app/countdown-parent.component.ts" region="vc" header="component-interaction/src/app/countdown-parent.component.ts">
</code-example> </code-example>
@ -374,7 +374,7 @@ Components outside this component subtree have no access to the service or their
This `MissionService` connects the `MissionControlComponent` to multiple `AstronautComponent` children. This `MissionService` connects the `MissionControlComponent` to multiple `AstronautComponent` children.
<code-example path="component-interaction/src/app/mission.service.ts" title="component-interaction/src/app/mission.service.ts"> <code-example path="component-interaction/src/app/mission.service.ts" header="component-interaction/src/app/mission.service.ts">
</code-example> </code-example>
@ -384,7 +384,7 @@ The `MissionControlComponent` both provides the instance of the service that it
(through the `providers` metadata array) and injects that instance into itself through its constructor: (through the `providers` metadata array) and injects that instance into itself through its constructor:
<code-example path="component-interaction/src/app/missioncontrol.component.ts" title="component-interaction/src/app/missioncontrol.component.ts"> <code-example path="component-interaction/src/app/missioncontrol.component.ts" header="component-interaction/src/app/missioncontrol.component.ts">
</code-example> </code-example>
@ -394,7 +394,7 @@ The `AstronautComponent` also injects the service in its constructor.
Each `AstronautComponent` is a child of the `MissionControlComponent` and therefore receives its parent's service instance: Each `AstronautComponent` is a child of the `MissionControlComponent` and therefore receives its parent's service instance:
<code-example path="component-interaction/src/app/astronaut.component.ts" title="component-interaction/src/app/astronaut.component.ts"> <code-example path="component-interaction/src/app/astronaut.component.ts" header="component-interaction/src/app/astronaut.component.ts">
</code-example> </code-example>
@ -433,7 +433,7 @@ Tests click buttons of both the parent `MissionControlComponent` and the `Astron
and verify that the history meets expectations: and verify that the history meets expectations:
<code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="bidirectional-service" title="component-interaction/e2e/src/app.e2e-spec.ts"> <code-example path="component-interaction/e2e/src/app.e2e-spec.ts" region="bidirectional-service" header="component-interaction/e2e/src/app.e2e-spec.ts">
</code-example> </code-example>

View File

@ -21,7 +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. The `styles` property takes an array of strings that contain CSS code.
Usually you give it one string, as in the following example: Usually you give it one string, as in the following example:
<code-example path="component-styles/src/app/hero-app.component.ts" title="src/app/hero-app.component.ts" linenums="false"> <code-example path="component-styles/src/app/hero-app.component.ts" header="src/app/hero-app.component.ts" linenums="false">
</code-example> </code-example>
## Style scope ## Style scope
@ -71,7 +71,7 @@ Use the `:host` pseudo-class selector to target styles in the element that *host
targeting elements *inside* the component's template). targeting elements *inside* the component's template).
<code-example path="component-styles/src/app/hero-details.component.css" region="host" title="src/app/hero-details.component.css" linenums="false"> <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>
The `:host` selector is the only way to target the host element. You can't reach The `:host` selector is the only way to target the host element. You can't reach
@ -83,7 +83,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. 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" title="src/app/hero-details.component.css" linenums="false"> <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>
### :host-context ### :host-context
@ -99,7 +99,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 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`. if some ancestor element has the CSS class `theme-light`.
<code-example path="component-styles/src/app/hero-details.component.css" region="hostcontext" title="src/app/hero-details.component.css" linenums="false"> <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>
### (deprecated) `/deep/`, `>>>`, and `::ng-deep` ### (deprecated) `/deep/`, `>>>`, and `::ng-deep`
@ -114,7 +114,7 @@ children and content children of the component.
The following example targets all `<h3>` elements, from the host element down The following example targets all `<h3>` elements, from the host element down
through this component to all of its child elements in the DOM. 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" title="src/app/hero-details.component.css" linenums="false"> <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>
@ -154,7 +154,7 @@ You can add a `styles` array property to the `@Component` decorator.
Each string in the array defines some CSS for this component. Each string in the array defines some CSS for this component.
<code-example path="component-styles/src/app/hero-app.component.ts" title="src/app/hero-app.component.ts (CSS inline)"> <code-example path="component-styles/src/app/hero-app.component.ts" header="src/app/hero-app.component.ts (CSS inline)">
</code-example> </code-example>
<div class="alert is-critical"> <div class="alert is-critical">
@ -164,7 +164,7 @@ They are _not inherited_ by any components nested within the template nor by any
</div> </div>
The CLI defines an empty `styles` array when you create the component with the `--inline-style` flag. The Angular CLI command [`ng generate component`](cli/generate) defines an empty `styles` array when you create the component with the `--inline-style` flag.
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate component hero-app --inline-style ng generate component hero-app --inline-style
@ -176,8 +176,8 @@ You can load styles from external CSS files by adding a `styleUrls` property
to a component's `@Component` decorator: to a component's `@Component` decorator:
<code-tabs> <code-tabs>
<code-pane title="src/app/hero-app.component.ts (CSS in file)" path="component-styles/src/app/hero-app.component.1.ts"></code-pane> <code-pane header="src/app/hero-app.component.ts (CSS in file)" path="component-styles/src/app/hero-app.component.1.ts"></code-pane>
<code-pane title="src/app/hero-app.component.css" path="component-styles/src/app/hero-app.component.css"></code-pane> <code-pane header="src/app/hero-app.component.css" path="component-styles/src/app/hero-app.component.css"></code-pane>
</code-tabs> </code-tabs>
<div class="alert is-critical"> <div class="alert is-critical">
@ -193,7 +193,7 @@ They are _not inherited_ by any components nested within the template nor by any
</div> </div>
The CLI creates an empty styles file for you by default and references that file in the component's generated `styleUrls`. When you use the Angular CLI command [`ng generate component`](cli/generate) without the `--inline-style` flag, it creates an empty styles file for you and references that file in the component's generated `styleUrls`.
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate component hero-app ng generate component hero-app
@ -204,19 +204,20 @@ ng generate component hero-app
You can embed CSS styles directly into the HTML template by putting them You can embed CSS styles directly into the HTML template by putting them
inside `<style>` tags. inside `<style>` tags.
<code-example path="component-styles/src/app/hero-controls.component.ts" region="inlinestyles" title="src/app/hero-controls.component.ts"> <code-example path="component-styles/src/app/hero-controls.component.ts" region="inlinestyles" header="src/app/hero-controls.component.ts">
</code-example> </code-example>
### Template link tags ### Template link tags
You can also write `<link>` tags into the component's HTML template. You can also write `<link>` tags into the component's HTML template.
<code-example path="component-styles/src/app/hero-team.component.ts" region="stylelink" title="src/app/hero-team.component.ts"> <code-example path="component-styles/src/app/hero-team.component.ts" region="stylelink" header="src/app/hero-team.component.ts">
</code-example> </code-example>
<div class="alert is-critical"> <div class="alert is-critical">
When building with the CLI, be sure to include the linked style file among the assets to be copied to the server as described in the [CLI documentation](https://github.com/angular/angular-cli/wiki/stories-asset-configuration). When building with the CLI, be sure to include the linked style file among the assets to be copied to the server as described in the [CLI wiki](https://github.com/angular/angular-cli/wiki/stories-asset-configuration).
<!-- 2018-10-16: The link above is still the best source for this information. -->
Once included, the CLI will include the stylesheet, whether the link tag's href URL is relative to the application root or the component file. Once included, the CLI will include the stylesheet, whether the link tag's href URL is relative to the application root or the component file.
@ -230,7 +231,7 @@ on the [MDN](https://developer.mozilla.org) site.
In this case, the URL is relative to the CSS file into which you're importing. In this case, the URL is relative to the CSS file into which you're importing.
<code-example path="component-styles/src/app/hero-details.component.css" region="import" title="src/app/hero-details.component.css (excerpt)"> <code-example path="component-styles/src/app/hero-details.component.css" region="import" header="src/app/hero-details.component.css (excerpt)">
</code-example> </code-example>
### External and global style files ### External and global style files
@ -239,7 +240,9 @@ When building with the CLI, you must configure the `angular.json` to include _al
Register **global** style files in the `styles` section which, by default, is pre-configured with the global `styles.css` file. Register **global** style files in the `styles` section which, by default, is pre-configured with the global `styles.css` file.
See the [CLI documentation](https://github.com/angular/angular-cli/wiki/stories-global-styles) to learn more. See the [CLI wiki](https://github.com/angular/angular-cli/wiki/stories-global-styles) to learn more.
<!-- 2018-10-16: The link above is still the best source for this information. -->
### Non-CSS style files ### Non-CSS style files
@ -259,8 +262,10 @@ The CLI build process runs the pertinent CSS preprocessor.
When generating a component file with `ng generate component`, the CLI emits an empty CSS styles file (`.css`) by default. When generating a component file with `ng generate component`, the CLI emits an empty CSS styles file (`.css`) by default.
You can configure the CLI to default to your preferred CSS preprocessor You can configure the CLI to default to your preferred CSS preprocessor
as explained in the [CLI documentation](https://github.com/angular/angular-cli/wiki/stories-css-preprocessors as explained in the [CLI wiki](https://github.com/angular/angular-cli/wiki/stories-css-preprocessors
"CSS Preprocessor integration"). "CSS Preprocessor integration").
<!-- 2018-10-16: The link above is still the best source for this information. -->
<div class="alert is-important"> <div class="alert is-important">
@ -298,7 +303,7 @@ Choose from the following modes:
To set the components encapsulation mode, use the `encapsulation` property in the component metadata: 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" title="src/app/quest-summary.component.ts" linenums="false"> <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>
`ShadowDom` view encapsulation only works on browsers that have native support `ShadowDom` view encapsulation only works on browsers that have native support

View File

@ -21,7 +21,7 @@ constructor, and lets the framework provide them.
The following example shows that `AppComponent` declares its dependence on `LoggerService` and `UserContext`. 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" title="src/app/app.component.ts" linenums="false"> <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>
@ -30,7 +30,7 @@ The following example shows that `AppComponent` declares its dependence on `Logg
`UserService`, another service that gathers information about a particular user. `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" title="user-context.service.ts (injection)" linenums="false"> <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>
@ -68,7 +68,7 @@ by providing that service *at the sub-root component for that branch*.
This example shows how to make a different instance of `HeroService` available to `HeroesBaseComponent` This example shows how to make a different instance of `HeroService` available to `HeroesBaseComponent`
by adding it to the `providers` array of the `@Component()` decorator of the sub-component. by adding it to the `providers` array of the `@Component()` decorator of the sub-component.
<code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="injection" title="src/app/sorted-heroes.component.ts (HeroesBaseComponent excerpt)"> <code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="injection" header="src/app/sorted-heroes.component.ts (HeroesBaseComponent excerpt)">
</code-example> </code-example>
@ -103,7 +103,7 @@ This is called *sandboxing* because each service and component instance has its
In this example, `HeroBiosComponent` presents three instances of `HeroBioComponent`. In this example, `HeroBiosComponent` presents three instances of `HeroBioComponent`.
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="simple" title="ap/hero-bios.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="simple" header="ap/hero-bios.component.ts">
</code-example> </code-example>
@ -111,7 +111,7 @@ In this example, `HeroBiosComponent` presents three instances of `HeroBioCompone
Each `HeroBioComponent` can edit a single hero's biography. Each `HeroBioComponent` can edit a single hero's biography.
`HeroBioComponent` relies on `HeroCacheService` to fetch, cache, and perform other persistence operations on that hero. `HeroBioComponent` relies on `HeroCacheService` to fetch, cache, and perform other persistence operations on that hero.
<code-example path="dependency-injection-in-action/src/app/hero-cache.service.ts" region="service" title="src/app/hero-cache.service.ts"> <code-example path="dependency-injection-in-action/src/app/hero-cache.service.ts" region="service" header="src/app/hero-cache.service.ts">
</code-example> </code-example>
@ -122,7 +122,7 @@ as they'd be competing with each other to determine which hero to cache.
Instead, each `HeroBioComponent` gets its *own* `HeroCacheService` instance Instead, each `HeroBioComponent` gets its *own* `HeroCacheService` instance
by listing `HeroCacheService` in its metadata `providers` array. by listing `HeroCacheService` in its metadata `providers` array.
<code-example path="dependency-injection-in-action/src/app/hero-bio.component.ts" region="component" title="src/app/hero-bio.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-bio.component.ts" region="component" header="src/app/hero-bio.component.ts">
</code-example> </code-example>
@ -149,7 +149,7 @@ By default, the DI framework searches for a provider in the injector hierarchy,
starting at the component's local injector of the component, and if necessary bubbling up starting at the component's local injector of the component, and if necessary bubbling up
through the injector tree until it reaches the root injector. through the injector tree until it reaches the root injector.
* The first injector configured with a provider supplies the the dependency (a service instance or value) to the constructor. * The first injector configured with a provider supplies the dependency (a service instance or value) to the constructor.
* If no provider is found in the root injector, the DI framework returns null to the constructor. * If no provider is found in the root injector, the DI framework returns null to the constructor.
@ -179,13 +179,13 @@ that parent component becomes the host. The following example covers this second
These decorators can be used individually or together, as shown in the example. These decorators can be used individually or together, as shown in the example.
This `HeroBiosAndContactsComponent` is a revision of `HeroBiosComponent` which you looked at [above](guide/dependency-injection-in-action#hero-bios-component). This `HeroBiosAndContactsComponent` is a revision of `HeroBiosComponent` which you looked at [above](guide/dependency-injection-in-action#hero-bios-component).
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="hero-bios-and-contacts" title="src/app/hero-bios.component.ts (HeroBiosAndContactsComponent)"> <code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="hero-bios-and-contacts" header="src/app/hero-bios.component.ts (HeroBiosAndContactsComponent)">
</code-example> </code-example>
Focus on the template: Focus on the template:
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="template" title="dependency-injection-in-action/src/app/hero-bios.component.ts" linenums="false"> <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>
@ -193,7 +193,7 @@ Now there's a new `<hero-contact>` element between the `<hero-bio>` tags.
Angular *projects*, or *transcludes*, the corresponding `HeroContactComponent` into the `HeroBioComponent` view, Angular *projects*, or *transcludes*, the corresponding `HeroContactComponent` into the `HeroBioComponent` view,
placing it in the `<ng-content>` slot of the `HeroBioComponent` template. 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" title="src/app/hero-bio.component.ts (template)" linenums="false"> <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>
@ -206,13 +206,13 @@ The result is shown below, with the hero's telephone number from `HeroContactCom
Here's `HeroContactComponent`, which demonstrates the qualifying decorators. Here's `HeroContactComponent`, which demonstrates the qualifying decorators.
<code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="component" title="src/app/hero-contact.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="component" header="src/app/hero-contact.component.ts">
</code-example> </code-example>
Focus on the constructor parameters. Focus on the constructor parameters.
<code-example path="dependency-injection-in-action/src/app/hero-contact.component.ts" region="ctor-params" title="src/app/hero-contact.component.ts" linenums="false"> <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>
@ -256,17 +256,17 @@ the app throws an exception when it cannot find the required logger at the host
Using a custom provider allows you to provide a concrete implementation for implicit dependencies, such as built-in browser APIs. The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`. Using a custom provider allows you to provide a concrete implementation for implicit dependencies, such as built-in browser APIs. The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`.
<code-example path="dependency-injection-in-action/src/app/storage.service.ts" title="src/app/storage.service.ts"> <code-example path="dependency-injection-in-action/src/app/storage.service.ts" header="src/app/storage.service.ts">
</code-example> </code-example>
The `factory` function returns the `localStorage` property that is attached to the browser window object. The `Inject` decorator is a constructor parameter used to specify a custom provider of a dependency. This custom provider can now be overriden during testing with a mock API of `localStorage` instead of interactive with real browser APIs. The `factory` function returns the `localStorage` property that is attached to the browser window object. The `Inject` decorator is a constructor parameter used to specify a custom provider of a dependency. This custom provider can now be overridden during testing with a mock API of `localStorage` instead of interactive with real browser APIs.
### Modify the provider search with `@Self` and `@SkipSelf` ### Modify the provider search with `@Self` and `@SkipSelf`
Providers can also be scoped by injector through constructor parameter decorators. The following example overrides the `BROWSER_STORAGE` token in the `Component` class `providers` with the `sessionStorage` browser API. The same `BrowserStorageService` is injected twice in the constructor, decorated with `@Self` and `@SkipSelf` to define which injector handles the provider dependency. Providers can also be scoped by injector through constructor parameter decorators. The following example overrides the `BROWSER_STORAGE` token in the `Component` class `providers` with the `sessionStorage` browser API. The same `BrowserStorageService` is injected twice in the constructor, decorated with `@Self` and `@SkipSelf` to define which injector handles the provider dependency.
<code-example path="dependency-injection-in-action/src/app/storage.component.ts" title="src/app/storage.component.ts"> <code-example path="dependency-injection-in-action/src/app/storage.component.ts" header="src/app/storage.component.ts">
</code-example> </code-example>
@ -283,7 +283,7 @@ As a result, you might need to access a component's DOM element.
To illustrate, here's a simplified version of `HighlightDirective` from To illustrate, here's a simplified version of `HighlightDirective` from
the [Attribute Directives](guide/attribute-directives) page. the [Attribute Directives](guide/attribute-directives) page.
<code-example path="dependency-injection-in-action/src/app/highlight.directive.ts" title="src/app/highlight.directive.ts"> <code-example path="dependency-injection-in-action/src/app/highlight.directive.ts" header="src/app/highlight.directive.ts">
</code-example> </code-example>
@ -297,7 +297,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, 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. 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" title="src/app/app.component.html (highlight)" linenums="false"> <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>
@ -323,7 +323,7 @@ Angular passes this token to the injector and assigns the result to the paramete
The following is a typical example. The following is a typical example.
<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="ctor" title="src/app/hero-bios.component.ts (component constructor injection)" linenums="false"> <code-example 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>
@ -366,7 +366,7 @@ It's visually simple: a few properties and the logs produced by a logger.
The code behind it customizes how and where the DI framework provides dependencies. The code behind it customizes how and where the DI framework provides dependencies.
The use cases illustrate different ways to use the [*provide* object literal](guide/dependency-injection-providers#provide) to associate a definition object with a DI token. The use cases illustrate different ways to use the [*provide* object literal](guide/dependency-injection-providers#provide) to associate a definition object with a DI token.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="hero-of-the-month" title="hero-of-the-month.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="hero-of-the-month" header="hero-of-the-month.component.ts">
</code-example> </code-example>
@ -384,7 +384,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. 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" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false"> <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>
@ -405,7 +405,7 @@ The title string literal is immediately available.
The `someHero` variable in this example was set earlier in the file as shown below. The `someHero` variable in this example was set earlier in the file as shown below.
You can't use a variable whose value will be defined later. You can't use a variable whose value will be defined later.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="some-hero" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="some-hero" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts">
</code-example> </code-example>
@ -425,7 +425,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`. 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" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false"> <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>
@ -446,7 +446,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: `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" title="src/app/date-logger.service.ts" linenums="false"> <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>
@ -458,7 +458,7 @@ The `useExisting` provider key lets you map one token to another.
In effect, the first token is an *alias* for the service associated with the second token, In effect, the first token is an *alias* for the service associated with the second token,
creating two ways to access the same service object. creating two ways to access the same service object.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-existing" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-existing" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts">
</code-example> </code-example>
@ -470,13 +470,13 @@ 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: 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" title="src/app/minimal-logger.service.ts" linenums="false"> <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>
The following example puts `MinimalLogger` to use in a simplified version of `HeroOfTheMonthComponent`. 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" title="src/app/hero-of-the-month.component.ts (minimal version)" linenums="false"> <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>
@ -507,7 +507,7 @@ This is illustrated in the following image, which displays the logging date.
The `useFactory` provider key lets you create a dependency object by calling a factory function, The `useFactory` provider key lets you create a dependency object by calling a factory function,
as in the following example. as in the following example.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-factory" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-factory" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts">
</code-example> </code-example>
@ -530,7 +530,7 @@ The `runnersUpFactory()` returns the *provider factory function*, which can use
the passed-in state value and the injected services `Hero` and `HeroService`. 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" title="runners-up.ts (excerpt)" linenums="false"> <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>
@ -570,13 +570,13 @@ That's the subject of the next section.
The previous *Hero of the Month* example used the `MinimalLogger` class The previous *Hero of the Month* example used the `MinimalLogger` class
as the token for a provider of `LoggerService`. as the token for a provider of `LoggerService`.
<code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-existing" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts"> <code-example path="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" region="use-existing" header="dependency-injection-in-action/src/app/hero-of-the-month.component.ts">
</code-example> </code-example>
`MinimalLogger` is an abstract class. `MinimalLogger` is an abstract class.
<code-example path="dependency-injection-in-action/src/app/minimal-logger.service.ts" title="dependency-injection-in-action/src/app/minimal-logger.service.ts" linenums="false"> <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>
@ -604,7 +604,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*. To minimize memory cost, however, the class should have *no implementation*.
The `MinimalLogger` transpiles to this unoptimized, pre-minified JavaScript for a constructor function. 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" title="dependency-injection-in-action/src/app/minimal-logger.service.ts" linenums="false"> <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>
@ -633,13 +633,13 @@ another token that happens to have the same name.
You encountered them twice in the *Hero of the Month* example, You encountered them twice in the *Hero of the Month* example,
in the *title* value provider and in the *runnersUp* factory provider. 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" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false"> <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>
You created the `TITLE` token like this: 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" title="dependency-injection-in-action/src/app/hero-of-the-month.component.ts" linenums="false"> <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>
@ -667,7 +667,7 @@ The `HeroesBaseComponent` can stand on its own.
It demands its own instance of `HeroService` to get heroes It demands its own instance of `HeroService` to get heroes
and displays them in the order they arrive from the database. and displays them in the order they arrive from the database.
<code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="heroes-base" title="src/app/sorted-heroes.component.ts (HeroesBaseComponent)"> <code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="heroes-base" header="src/app/sorted-heroes.component.ts (HeroesBaseComponent)">
</code-example> </code-example>
@ -693,7 +693,7 @@ You must provide the `HeroService` again for *this* component,
then pass it down to the base class inside the constructor. then pass it down to the base class inside the constructor.
<code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="sorted-heroes" title="src/app/sorted-heroes.component.ts (SortedHeroesComponent)"> <code-example path="dependency-injection-in-action/src/app/sorted-heroes.component.ts" region="sorted-heroes" header="src/app/sorted-heroes.component.ts (SortedHeroesComponent)">
</code-example> </code-example>
@ -731,7 +731,7 @@ appear *above* the class definition.
Break the circularity with `forwardRef`. Break the circularity with `forwardRef`.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" title="parent-finder.component.ts (AlexComponent providers)" linenums="false"> <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>

View File

@ -40,7 +40,7 @@ In the following example, the parent `AlexComponent` has several children includ
{@a alex} {@a alex}
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-1" title="parent-finder.component.ts (AlexComponent v.1)" linenums="false"> <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>
@ -49,7 +49,7 @@ In the following example, the parent `AlexComponent` has several children includ
*Cathy* reports whether or not she has access to *Alex* *Cathy* reports whether or not she has access to *Alex*
after injecting an `AlexComponent` into her constructor: after injecting an `AlexComponent` into her constructor:
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="cathy" title="parent-finder.component.ts (CathyComponent)" linenums="false"> <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>
@ -98,7 +98,7 @@ inject its parent via the parent's base class*.
The sample's `CraigComponent` explores this question. [Looking back](#alex), The sample's `CraigComponent` explores this question. [Looking back](#alex),
you see that the `Alex` component *extends* (*inherits*) from a class named `Base`. 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" title="parent-finder.component.ts (Alex class signature)" linenums="false"> <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>
@ -106,13 +106,13 @@ you see that the `Alex` component *extends* (*inherits*) from a class named `Bas
The `CraigComponent` tries to inject `Base` into its `alex` constructor parameter and reports if it succeeded. 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" title="parent-finder.component.ts (CraigComponent)" linenums="false"> <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>
Unfortunately, this does'nt work. Unfortunately, this doesn't work.
The <live-example name="dependency-injection-in-action"></live-example> The <live-example name="dependency-injection-in-action"></live-example>
confirms that the `alex` parameter is null. confirms that the `alex` parameter is null.
*You cannot inject a parent by its base class.* *You cannot inject a parent by its base class.*
@ -138,7 +138,7 @@ and add that provider to the `providers` array of the `@Component()` metadata fo
{@a alex-providers} {@a alex-providers}
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-providers" title="parent-finder.component.ts (AlexComponent providers)" linenums="false"> <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>
@ -149,7 +149,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, *Carol*, the third of *Alex*'s child components, injects the parent into its `parent` parameter,
the same way you've done it before. the same way you've done it before.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="carol-class" title="parent-finder.component.ts (CarolComponent class)" linenums="false"> <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>
@ -177,7 +177,7 @@ That means he must both *inject* the `Parent` class interface to get *Alice* and
Here's *Barry*. Here's *Barry*.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="barry" title="parent-finder.component.ts (BarryComponent)" linenums="false"> <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>
@ -190,11 +190,11 @@ For now, focus on *Barry*'s constructor.
<code-tabs> <code-tabs>
<code-pane title="Barry's constructor" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="barry-ctor"> <code-pane header="Barry's constructor" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="barry-ctor">
</code-pane> </code-pane>
<code-pane title="Carol's constructor" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="carol-ctor"> <code-pane header="Carol's constructor" path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="carol-ctor">
</code-pane> </code-pane>
@ -229,7 +229,7 @@ You [learned earlier](guide/dependency-injection-in-action#class-interface) that
The example defines a `Parent` class interface. The example defines a `Parent` class interface.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="parent" title="parent-finder.component.ts (Parent class-interface)" linenums="false"> <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>
@ -241,7 +241,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. 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" title="parent-finder.component.ts (AliceComponent class signature)" linenums="false"> <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>
@ -251,7 +251,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, Although `AlexComponent` has a `name` property, as required by its `Base` class,
its class signature doesn't mention `Parent`. its class signature doesn't mention `Parent`.
<code-example path="dependency-injection-in-action/src/app/parent-finder.component.ts" region="alex-class-signature" title="parent-finder.component.ts (AlexComponent class signature)" linenums="false"> <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>
@ -277,19 +277,19 @@ 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, Writing variations of the same parent *alias provider* gets old quickly,
especially this awful mouthful with a [*forwardRef*](guide/dependency-injection-in-action#forwardref). 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" title="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false"> <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>
You can extract that logic into a helper function like the following. 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" title="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false"> <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>
Now you can add a simpler, more meaningful parent provider to your components. 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" title="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false"> <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>
@ -299,14 +299,14 @@ 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. 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" title="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false"> <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>
And here's how you could use it with a different parent type. 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" title="dependency-injection-in-action/src/app/parent-finder.component.ts" linenums="false"> <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>

View File

@ -130,7 +130,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. These configuration objects aren't always instances of a class.
They can be object literals, as shown in the following example. They can be object literals, as shown in the following example.
<code-example path="dependency-injection/src/app/app.config.ts" region="config" title="src/app/app.config.ts (excerpt)" linenums="false"> <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>
{@a interface-not-valid-token} {@a interface-not-valid-token}
@ -147,7 +147,7 @@ In TypeScript, an interface is a design-time artifact, and doesn't have a runtim
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-9-ctor-interface" linenums="false"> <code-example path="dependency-injection/src/app/providers.component.ts" region="provider-9-ctor-interface" linenums="false">
</code-example> </code-example>
<div class="alert-is-helpful"> <div class="alert is-helpful">
This might seem strange if you're used to dependency injection in strongly typed languages where an interface is the preferred dependency lookup key. This might seem strange if you're used to dependency injection in strongly typed languages where an interface is the preferred dependency lookup key.
However, JavaScript, doesn't have interfaces, so when TypeScript is transpiled to JavaScript, the interface disappears. However, JavaScript, doesn't have interfaces, so when TypeScript is transpiled to JavaScript, the interface disappears.
@ -157,13 +157,13 @@ There is no interface type information left for Angular to find at runtime.
One alternative is to provide and inject the configuration object in an NgModule like `AppModule`. One alternative is to provide and inject the configuration object in an NgModule like `AppModule`.
<code-example path="dependency-injection/src/app/app.module.ts" region="providers" title="src/app/app.module.ts (providers)"></code-example> <code-example path="dependency-injection/src/app/app.module.ts" region="providers" header="src/app/app.module.ts (providers)"></code-example>
Another solution to choosing a provider token for non-class dependencies is Another solution to choosing a provider token for non-class dependencies is
to define and use an `InjectionToken` object. to define and use an `InjectionToken` object.
The following example shows how to define such a token. The following example shows how to define such a token.
<code-example path="dependency-injection/src/app/app.config.ts" region="token" title="src/app/app.config.ts" linenums="false"> <code-example path="dependency-injection/src/app/app.config.ts" region="token" header="src/app/app.config.ts" linenums="false">
</code-example> </code-example>
The type parameter, while optional, conveys the dependency's type to developers and tooling. The type parameter, while optional, conveys the dependency's type to developers and tooling.
@ -177,10 +177,10 @@ Register the dependency provider using the `InjectionToken` object:
Now you can inject the configuration object into any constructor that needs it, with Now you can inject the configuration object into any constructor that needs it, with
the help of an `@Inject()` parameter decorator. the help of an `@Inject()` parameter decorator.
<code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" title="src/app/app.component.ts" linenums="false"> <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>
<div class="alert-is-helpful"> <div class="alert is-helpful">
Although the `AppConfig` interface plays no role in dependency injection, Although the `AppConfig` interface plays no role in dependency injection,
it supports typing of the configuration object within the class. it supports typing of the configuration object within the class.
@ -215,21 +215,21 @@ who is authorized and who isn't.
To resolve this, we give the `HeroService` constructor a boolean flag to control display of secret heroes. 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" title="src/app/heroes/hero.service.ts (excerpt)" linenums="false"> <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>
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`. 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. A factory provider needs a factory function.
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="factory" title="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false"> <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>
Although `HeroService` has no access to `UserService`, the factory function does. Although `HeroService` has no access to `UserService`, the factory function does.
You inject both `Logger` and `UserService` into the factory provider You inject both `Logger` and `UserService` into the factory provider
and let the injector pass them along to the factory function. 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" title="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false"> <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>
* The `useFactory` field tells Angular that the provider is a factory function whose implementation is `heroServiceFactory`. * The `useFactory` field tells Angular that the provider is a factory function whose implementation is `heroServiceFactory`.
@ -248,10 +248,10 @@ The following shows the new and the old implementations side-by-side.
<code-tabs> <code-tabs>
<code-pane title="src/app/heroes/heroes.component (v3)" path="dependency-injection/src/app/heroes/heroes.component.ts"> <code-pane header="src/app/heroes/heroes.component (v3)" path="dependency-injection/src/app/heroes/heroes.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/heroes.component (v2)" path="dependency-injection/src/app/heroes/heroes.component.1.ts"> <code-pane header="src/app/heroes/heroes.component (v2)" path="dependency-injection/src/app/heroes/heroes.component.1.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -293,7 +293,7 @@ When you provide multiple sets of routes using [RouterModule.forRoot](api/router
and [RouterModule.forChild](api/router/RouterModule#forchild) in a single module, and [RouterModule.forChild](api/router/RouterModule#forchild) in a single module,
the [ROUTES](api/router/ROUTES) token combines all the different provided sets of routes into a single value. the [ROUTES](api/router/ROUTES) token combines all the different provided sets of routes into a single value.
<div class="alert-is-helpful> <div class="alert is-helpful>
Search for [Constants in API documentation](api?type=const) to find more built-in tokens. Search for [Constants in API documentation](api?type=const) to find more built-in tokens.
@ -309,7 +309,7 @@ When providers are tree-shakable, the Angular compiler removes the associated
services from the final output when it determines that they are not used in your application. services from the final output when it determines that they are not used in your application.
This significantly reduces the size of your bundles. This significantly reduces the size of your bundles.
<div class="alert-is-helpful"> <div class="alert is-helpful">
Ideally, if an application isn't injecting a service, it shouldn't be included in the final output. Ideally, if an application isn't injecting a service, it shouldn't be included in the final output.
However, Angular has to be able to identify at build time whether the service will be required or not. However, Angular has to be able to identify at build time whether the service will be required or not.
@ -322,13 +322,13 @@ Thus, services provided at the NgModule or component level are not tree-shakable
The following example of non-tree-shakable providers in Angular configures a service provider for the injector of an NgModule. 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" title="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" linenums="false"> </code-example>
This module can then be imported into your application module This module can then be imported into your application module
to make the service available for injection in your app, to make the service available for injection in your app,
as shown in the following example. as shown in the following example.
<code-example path="dependency-injection/src/app/tree-shaking/app.module.ts" title="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" linenums="false"> </code-example>
When `ngc` runs, it compiles `AppModule` into a module factory, which contains definitions for all the providers declared in all the modules it includes. At runtime, this factory becomes an injector that instantiates these services. 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,13 +340,13 @@ 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. The following example shows the tree-shakable equivalent to the `ServiceModule` example above.
<code-example path="dependency-injection/src/app/tree-shaking/service.ts" title="src/app/tree-shaking/service.ts" linenums="false"> </code-example> <code-example path="dependency-injection/src/app/tree-shaking/service.ts" header="src/app/tree-shaking/service.ts" linenums="false"> </code-example>
The service can be instantiated by configuring a factory function, as in the following 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" title="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" linenums="false"> </code-example>
<div class="alert-is-helpful"> <div class="alert is-helpful">
To override a tree-shakable provider, configure the injector of a specific NgModule or component with another provider, using the `providers: []` array syntax of the `@NgModule()` or `@Component()` decorator. To override a tree-shakable provider, configure the injector of a specific NgModule or component with another provider, using the `providers: []` array syntax of the `@NgModule()` or `@Component()` decorator.

View File

@ -9,7 +9,7 @@ DI is a coding pattern in which a class asks for dependencies from external sour
In Angular, the DI framework provides declared dependencies to a class when that class is instantiated. This guide explains how DI works in Angular, and how you use it to make your apps flexible, efficient, and robust, as well as testable and maintainable. In Angular, the DI framework provides declared dependencies to a class when that class is instantiated. This guide explains how DI works in Angular, and how you use it to make your apps flexible, efficient, and robust, as well as testable and maintainable.
<div class="alert-is-helpful"> <div class="alert is-helpful">
You can run the <live-example></live-example> of the sample app that accompanies this guide. You can run the <live-example></live-example> of the sample app that accompanies this guide.
@ -19,16 +19,16 @@ Start by reviewing this simplified version of the _heroes_ feature
from the [The Tour of Heroes](tutorial/). This simple version doesn't use DI; we'll walk through converting it to do so. from the [The Tour of Heroes](tutorial/). This simple version doesn't use DI; we'll walk through converting it to do so.
<code-tabs> <code-tabs>
<code-pane title="src/app/heroes/heroes.component.ts" path="dependency-injection/src/app/heroes/heroes.component.1.ts" region="v1"> <code-pane header="src/app/heroes/heroes.component.ts" path="dependency-injection/src/app/heroes/heroes.component.1.ts" region="v1">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/hero-list.component.ts" path="dependency-injection/src/app/heroes/hero-list.component.1.ts"> <code-pane header="src/app/heroes/hero-list.component.ts" path="dependency-injection/src/app/heroes/hero-list.component.1.ts">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/hero.ts" path="dependency-injection/src/app/heroes/hero.ts"> <code-pane header="src/app/heroes/hero.ts" path="dependency-injection/src/app/heroes/hero.ts">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/mock-heroes.ts" path="dependency-injection/src/app/heroes/mock-heroes.ts"> <code-pane header="src/app/heroes/mock-heroes.ts" path="dependency-injection/src/app/heroes/mock-heroes.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -39,7 +39,7 @@ Its only purpose is to display `HeroListComponent`, which displays a list of her
This version of the `HeroListComponent` gets heroes from the `HEROES` array, an in-memory collection This version of the `HeroListComponent` gets heroes from the `HEROES` array, an in-memory collection
defined in a separate `mock-heroes` file. defined in a separate `mock-heroes` file.
<code-example title="src/app/heroes/hero-list.component.ts (class)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts" region="class"> <code-example header="src/app/heroes/hero-list.component.ts (class)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts" region="class">
</code-example> </code-example>
This approach works for prototyping, but is not robust or maintainable. This approach works for prototyping, but is not robust or maintainable.
@ -52,7 +52,7 @@ replace every use of the `HEROES` mock data.
The DI framework lets you supply data to a component from an injectable _service_ class, defined in its own file. To demonstrate, we'll create an injectable service class that provides a list of heroes, and register that class as a provider of that service. The DI framework lets you supply data to a component from an injectable _service_ class, defined in its own file. To demonstrate, we'll create an injectable service class that provides a list of heroes, and register that class as a provider of that service.
<div class="alert-is-helpful"> <div class="alert is-helpful">
Having multiple classes in the same file can be confusing. We generally recommend that you define components and services in separate files. Having multiple classes in the same file can be confusing. We generally recommend that you define components and services in separate files.
@ -68,7 +68,7 @@ See an example in the [DI Cookbook](guide/dependency-injection-in-action#forward
### Create an injectable service class ### Create an injectable service class
The [**Angular CLI**](https://cli.angular.io/) can generate a new `HeroService` class in the `src/app/heroes` folder with this command. The [Angular CLI](cli) can generate a new `HeroService` class in the `src/app/heroes` folder with this command.
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate service heroes/hero ng generate service heroes/hero
@ -76,12 +76,12 @@ ng generate service heroes/hero
The command creates the following `HeroService` skeleton. The command creates the following `HeroService` skeleton.
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" title="src/app/heroes/hero.service.ts (CLI-generated)"> <code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" header="src/app/heroes/hero.service.ts (CLI-generated)">
</code-example> </code-example>
The `@Injectable()` is an essential ingredient in every Angular service definition. The rest of the class has been written to expose a `getHeroes` method that returns the same mock data as before. (A real app would probably get its data asynchronously from a remote server, but we'll ignore that to focus on the mechanics of injecting the service.) The `@Injectable()` is an essential ingredient in every Angular service definition. The rest of the class has been written to expose a `getHeroes` method that returns the same mock data as before. (A real app would probably get its data asynchronously from a remote server, but we'll ignore that to focus on the mechanics of injecting the service.)
<code-example path="dependency-injection/src/app/heroes/hero.service.3.ts" title="src/app/heroes/hero.service.ts"> <code-example path="dependency-injection/src/app/heroes/hero.service.3.ts" header="src/app/heroes/hero.service.ts">
</code-example> </code-example>
@ -147,7 +147,7 @@ In order for `HeroListComponent` to get heroes from `HeroService`, it needs to a
You can tell Angular to inject a dependency in a component's constructor by specifying a **constructor parameter with the dependency type**. Here's the `HeroListComponent` constructor, asking for the `HeroService` to be injected. You can tell Angular to inject a dependency in a component's constructor by specifying a **constructor parameter with the dependency type**. Here's the `HeroListComponent` constructor, asking for the `HeroService` to be injected.
<code-example title="src/app/heroes/hero-list.component (constructor signature)" path="dependency-injection/src/app/heroes/hero-list.component.ts" <code-example header="src/app/heroes/hero-list.component (constructor signature)" path="dependency-injection/src/app/heroes/hero-list.component.ts"
region="ctor-signature"> region="ctor-signature">
</code-example> </code-example>
@ -155,10 +155,10 @@ Of course, `HeroListComponent` should do something with the injected `HeroServic
Here's the revised component, making use of the injected service, side-by-side with the previous version for comparison. Here's the revised component, making use of the injected service, side-by-side with the previous version for comparison.
<code-tabs> <code-tabs>
<code-pane title="hero-list.component (with DI)" path="dependency-injection/src/app/heroes/hero-list.component.2.ts"> <code-pane header="hero-list.component (with DI)" path="dependency-injection/src/app/heroes/hero-list.component.2.ts">
</code-pane> </code-pane>
<code-pane title="hero-list.component (without DI)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts"> <code-pane header="hero-list.component (without DI)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -197,7 +197,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 For example, you can create a new `HeroListComponent` with a mock service that you can manipulate
under test. under test.
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" title="src/app/test.component.ts" linenums="false"> <code-example path="dependency-injection/src/app/test.component.ts" region="spec" header="src/app/test.component.ts" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -217,13 +217,13 @@ Here is the revised `HeroService` that injects `Logger`, side by side with the p
<code-tabs> <code-tabs>
<code-pane title="src/app/heroes/hero.service (v2)" path="dependency-injection/src/app/heroes/hero.service.2.ts"> <code-pane header="src/app/heroes/hero.service (v2)" path="dependency-injection/src/app/heroes/hero.service.2.ts">
</code-pane> </code-pane>
<code-pane title="src/app/heroes/hero.service (v1)" path="dependency-injection/src/app/heroes/hero.service.1.ts"> <code-pane header="src/app/heroes/hero.service (v1)" path="dependency-injection/src/app/heroes/hero.service.1.ts">
</code-pane> </code-pane>
<code-pane title="src/app/logger.service" <code-pane header="src/app/logger.service"
path="dependency-injection/src/app/logger.service.ts"> path="dependency-injection/src/app/logger.service.ts">
</code-pane> </code-pane>
@ -238,9 +238,9 @@ If Angular can't find that parameter information, it throws an error.
Angular can only find the parameter information _if the class has a decorator of some kind_. Angular can only find the parameter information _if the class has a decorator of some kind_.
The `@Injectable()` decorator is the standard decorator for service classes. The `@Injectable()` decorator is the standard decorator for service classes.
<div class="alert-is-helpful"> <div class="alert is-helpful">
The decorator requirement is imposed by TypeScript. TypeScript normally discards parameter type information when it [transpiles]((guide/glossary#transpile) the code to JavaScript. TypeScript preserves this information if the class has a decorator and the `emitDecoratorMetadata` compiler option is set `true` in TypeScript's `tsconfig.json` configuration file. The CLI configures `tsconfig.json` with `emitDecoratorMetadata: true`. The decorator requirement is imposed by TypeScript. TypeScript normally discards parameter type information when it [transpiles](guide/glossary#transpile) the code to JavaScript. TypeScript preserves this information if the class has a decorator and the `emitDecoratorMetadata` compiler option is set `true` in TypeScript's `tsconfig.json` configuration file. The CLI configures `tsconfig.json` with `emitDecoratorMetadata: true`.
This means you're responsible for putting `@Injectable()` on your service classes. This means you're responsible for putting `@Injectable()` on your service classes.
@ -260,14 +260,14 @@ In simple examples, the dependency value is an *instance*, and
the class *type* serves as its own lookup key. 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: 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" title="src/app/injector.component.ts" linenums="false"> <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>
The behavior is similar when you write a constructor that requires an injected class-based dependency. 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, When you define a constructor parameter with the `HeroService` class type,
Angular knows to inject the service associated with that `HeroService` class token: Angular knows to inject the service associated with that `HeroService` class token:
<code-example path="dependency-injection/src/app/heroes/hero-list.component.ts" region="ctor-signature" title="src/app/heroes/hero-list.component.ts"> <code-example path="dependency-injection/src/app/heroes/hero-list.component.ts" region="ctor-signature" header="src/app/heroes/hero-list.component.ts">
</code-example> </code-example>
Many dependency values are provided by classes, but not all. The expanded *provide* object lets you associate different kinds of providers with a DI token. Many dependency values are provided by classes, but not all. The expanded *provide* object lets you associate different kinds of providers with a DI token.
@ -295,7 +295,7 @@ 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 don't register a logger provider anywhere, the injector sets the
value of `logger` to null. value of `logger` to null.
<div class="alert-is-helpful"> <div class="alert is-helpful">
`@Inject()` and `@Optional()` are _parameter decorators_. They alter the way the DI framework provides a dependency, by annotating the dependency parameter on the constructor of the class that requires the dependency. `@Inject()` and `@Optional()` are _parameter decorators_. They alter the way the DI framework provides a dependency, by annotating the dependency parameter on the constructor of the class that requires the dependency.

View File

@ -1,29 +1,28 @@
# Deployment # Deployment
When you are ready to deploy your Angular application to a remote server, you have various options for When you are ready to deploy your Angular application to a remote server, you have various options for
deployment. You may need to configure deployment.
{@a dev-deploy} {@a dev-deploy}
{@a copy-files} {@a copy-files}
## Simplest deployment possible ## Simplest deployment possible
For the simplest deployment, build for development and copy the output directory to a web server. For the simplest deployment, create a production build and copy the output directory to a web server.
1. Start with the development build 1. Start with the production build:
<code-example language="none" class="code-shell"> <code-example language="none" class="code-shell">
ng build ng build --prod
</code-example> </code-example>
2. Copy _everything_ within the output folder (`dist/` by default) to a folder on the server. 2. Copy _everything_ within the output folder (`dist/` by default) to a folder on the server.
3. Configure the server to redirect requests for missing files to `index.html`. 3. Configure the server to redirect requests for missing files to `index.html`.
Learn more about server-side redirects [below](guide/deployment#fallback). Learn more about server-side redirects [below](#fallback).
This is _not_ a production deployment. It's not optimized and it won't be fast for users. This is the simplest production-ready deployment of your application.
It might be good enough for sharing your progress and ideas internally with managers, teammates, and other stakeholders. For the next steps in deployment, see [Optimize for production](#optimize).
{@a deploy-to-github} {@a deploy-to-github}
@ -31,23 +30,23 @@ It might be good enough for sharing your progress and ideas internally with mana
Another simple way to deploy your Angular app is to use [GitHub Pages](https://help.github.com/articles/what-is-github-pages/). Another simple way to deploy your Angular app is to use [GitHub Pages](https://help.github.com/articles/what-is-github-pages/).
1. You will need to [create a GitHub account](https://github.com/join) if you don't have one, then [create a repository](https://help.github.com/articles/create-a-repo/) for your project. 1. You need to [create a GitHub account](https://github.com/join) if you don't have one, and then [create a repository](https://help.github.com/articles/create-a-repo/) for your project.
Make a note of the user name and project name in GitHub. Make a note of the user name and project name in GitHub.
1. Build your project using Github project name, with the following CLI command: 1. Build your project using Github project name, with the Angular CLI command [`ng build`](cli/build) and the options shown here:
<code-example language="none" class="code-shell"> <code-example language="none" class="code-shell">
ng build --prod --output-path docs --base-href <project_name> ng build --prod --output-path docs --base-href <project_name>
</code-example> </code-example>
1. When the build is complete, make a copy of `docs/index.html` and name it `docs/404.html`. 1. When the build is complete, make a copy of `docs/index.html` and name it `docs/404.html`.
1. Commit your changes and push. 1. Commit your changes and push.
1. On the GitHub project page, configure it to [publish from the docs folder](https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch). 1. On the GitHub project page, configure it to [publish from the docs folder](https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch).
You can see your deployed page at `https://<user_name>.github.io/<project_name>/`. You can see your deployed page at `https://<user_name>.github.io/<project_name>/`.
<div class="alert-is-helpful> <div class="alert is-helpful>
Check out [angular-cli-ghpages](https://github.com/angular-buch/angular-cli-ghpages), a full featured package that does all this for you and has extra functionality. Check out [angular-cli-ghpages](https://github.com/angular-buch/angular-cli-ghpages), a full featured package that does all this for you and has extra functionality.
@ -97,51 +96,6 @@ There is no single configuration that works for every server.
The following sections describe configurations for some of the most popular servers. The following sections describe configurations for some of the most popular servers.
The list is by no means exhaustive, but should provide you with a good starting point. The list is by no means exhaustive, but should provide you with a good starting point.
#### Development servers
During development, the `ng serve` command lets you run your app in a local browser.
The CLI recompiles the application each time you save a file,
and reloads the browser with the newly compiled application.
The app is hosted in local memory and served on `http://localhost:4200/`, using [webpack-dev-server](https://webpack.js.org/guides/development/#webpack-dev-server).
{@a serve-from-disk}
Later in development, you might want a closer approximation of how your app will behave when deployed.
You can output your distribution folder (`dist`) to disk, but you need to install a different web server.
Try installing [lite-server](https://github.com/johnpapa/lite-server); like `webpack-dev-server`, it can automatically reload your browser when you write new files.
To get the live-reload experience, you will need to run two terminals.
The first runs the build in a watch mode and compiles the application to the `dist` folder.
The second runs the web server against the `dist` folder.
The combination of these two processes provides the same behavior as `ng serve`.
1. Start the build in terminal A:
<code-example language="none" class="code-shell">
ng build --watch
</code-example>
1. Start the web server in terminal B:
<code-example language="none" class="code-shell">
lite-server --baseDir="dist"
</code-example>
The default browser opens to the appropriate URL.
* [Lite-Server](https://github.com/johnpapa/lite-server): the default dev server installed with the
[Quickstart repo](https://github.com/angular/quickstart) is pre-configured to fallback to `index.html`.
* [Webpack-Dev-Server](https://github.com/webpack/webpack-dev-server): setup the
`historyApiFallback` entry in the dev server options as follows:
<code-example>
historyApiFallback: {
disableDotRule: true,
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml']
}
</code-example>
#### Production servers
* [Apache](https://httpd.apache.org/): add a * [Apache](https://httpd.apache.org/): add a
[rewrite rule](http://httpd.apache.org/docs/current/mod/mod_rewrite.html) to the `.htaccess` file as shown [rewrite rule](http://httpd.apache.org/docs/current/mod/mod_rewrite.html) to the `.htaccess` file as shown
(https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/): (https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/):
@ -230,19 +184,9 @@ Read about how to enable CORS for specific servers at
{@a optimize} {@a optimize}
## Optimize for production ## Production optimizations
Although deploying directly from the development environment works, The `--prod` _meta-flag_ engages the following build optimization features.
you can generate an optimized build with additional CLI command line flags,
starting with `--prod`.
### Build with _--prod_
<code-example language="none" class="code-shell">
ng build --prod
</code-example>
The `--prod` _meta-flag_ engages the following optimization features.
* [Ahead-of-Time (AOT) Compilation](guide/aot-compiler): pre-compiles Angular component templates. * [Ahead-of-Time (AOT) Compilation](guide/aot-compiler): pre-compiles Angular component templates.
* [Production mode](#enable-prod-mode): deploys the production environment which enables _production mode_. * [Production mode](#enable-prod-mode): deploys the production environment which enables _production mode_.
@ -251,26 +195,22 @@ The `--prod` _meta-flag_ engages the following optimization features.
* Uglification: rewrites code to use short, cryptic variable and function names. * Uglification: rewrites code to use short, cryptic variable and function names.
* Dead code elimination: removes unreferenced modules and much unused code. * Dead code elimination: removes unreferenced modules and much unused code.
The remaining [copy deployment steps](#copy-files) are the same as before. See [`ng build`](cli/build) for more about CLI build options and what they do.
See [Building and serving Angular apps](guide/build)
for more about about CLI build options and what they do.
{@a enable-prod-mode} {@a enable-prod-mode}
### Enable production mode ### Enable runtime production mode
Angular apps run in development mode by default, as you can see by the following message on the browser In addition to build optimizations, Angular also has a runtime production mode. Angular apps run in development mode by default, as you can see by the following message on the browser console:
console:
<code-example format="nocode"> <code-example format="nocode">
Angular is running in the development mode. Call enableProdMode() to enable the production mode. Angular is running in the development mode. Call enableProdMode() to enable the production mode.
</code-example> </code-example>
Switching to _production mode_ can make it run faster by disabling development specific checks such as the dual change detection cycles. Switching to _production mode_ makes it run faster by disabling development specific checks such as the dual change detection cycles.
Building for production (or appending the `--environment=prod` flag) enables _production mode_ When you enable production builds via `--prod` command line flag, the runtime production mode is enabled as well.
Look at the CLI-generated `main.ts` to see how this works.
{@a lazy-loading} {@a lazy-loading}
@ -284,7 +224,7 @@ Configure the Angular Router to defer loading of all other modules (and their as
or by [_lazy loading_](guide/router#asynchronous-routing "Lazy loading") or by [_lazy loading_](guide/router#asynchronous-routing "Lazy loading")
them on demand. them on demand.
<div class="alert-is-helpful> <div class="alert is-helpful>
#### Don't eagerly import something from a lazy-loaded module #### Don't eagerly import something from a lazy-loaded module
@ -294,7 +234,7 @@ If you do that, the module will be loaded immediately.
The bundling configuration must take lazy loading into consideration. The bundling configuration must take lazy loading into consideration.
Because lazy-loaded modules aren't imported in JavaScript, bundlers exclude them by default. Because lazy-loaded modules aren't imported in JavaScript, bundlers exclude them by default.
Bundlers don't know about the router configuration and can't create separate bundles for lazy-loaded modules. Bundlers don't know about the router configuration and can't create separate bundles for lazy-loaded modules.
You would have to create these bundles manually. You would have to create these bundles manually.
The CLI runs the The CLI runs the
@ -389,10 +329,10 @@ for the missing files. Look at where it _tried_ to find those files and adjust t
## Building and serving for deployment ## Building and serving for deployment
When you are designing and developing applications, you typically use `ng serve` to build your app for fast, local, iterative development. When you are designing and developing applications, you typically use `ng serve` to build your app for fast, local, iterative development.
When you are ready to deploy, however, you must use the `ng build` command to build the app and deploy the build artifacts elsewhere. When you are ready to deploy, however, you must use the `ng build` command to build the app and deploy the build artifacts elsewhere.
Both `ng build` and `ng serve` clear the output folder before they build the project, but only the `build` command writes the generated build artifacts to the output folder. Both `ng build` and `ng serve` clear the output folder before they build the project, but only the `ng build` command writes the generated build artifacts to the output folder.
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -401,13 +341,13 @@ To output to a different folder, change the `outputPath` in `angular.json`.
</div> </div>
The`serve` command builds, watches, and serves the application from local memory, using a local development server. The `ng serve` command builds, watches, and serves the application from local memory, using a local development server.
When you have deployed your app to another server, however, you might still want to serve the app so that you can continue to see changes that you make in it. When you have deployed your app to another server, however, you might still want to serve the app so that you can continue to see changes that you make in it.
You can do this by adding the `--watch` option to the `build` command. You can do this by adding the `--watch` option to the `ng build` command.
``` ```
ng build --watch ng build --watch
``` ```
Like the `serve` command, this regenerates output files when source files change. Like the `ng serve` command, this regenerates output files when source files change.
For complete details of the CLI commands and configuration options, see the *CLI Reference (link TBD)*. For complete details of the CLI commands, see the [CLI command reference](cli).

View File

@ -31,7 +31,7 @@ The easiest way to display a component property
is to bind the property name through interpolation. is to bind the property name through interpolation.
With interpolation, you put the property name in the view template, enclosed in double curly braces: `{{myHero}}`. With interpolation, you put the property name in the view template, enclosed in double curly braces: `{{myHero}}`.
Follow the [quickstart](guide/quickstart) instructions for creating a new project Follow the [Getting Started](guide/quickstart) instructions for creating a new project
named <code>displaying-data</code>. named <code>displaying-data</code>.
Delete the <code>app.component.html</code> file. It is not needed for this example. Delete the <code>app.component.html</code> file. It is not needed for this example.
@ -42,7 +42,7 @@ changing the template and the body of the component.
When you're done, it should look like this: When you're done, it should look like this:
<code-example path="displaying-data/src/app/app.component.1.ts" title="src/app/app.component.ts"> <code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts">
</code-example> </code-example>
@ -54,7 +54,7 @@ The template displays the two component properties using double curly brace
interpolation: interpolation:
<code-example path="displaying-data/src/app/app.component.1.ts" linenums="false" title="src/app/app.component.ts (template)" region="template"> <code-example path="displaying-data/src/app/app.component.1.ts" linenums="false" header="src/app/app.component.ts (template)" region="template">
</code-example> </code-example>
@ -98,7 +98,7 @@ The CSS `selector` in the `@Component` decorator specifies an element named `<ap
That element is a placeholder in the body of your `index.html` file: That element is a placeholder in the body of your `index.html` file:
<code-example path="displaying-data/src/index.html" linenums="false" title="src/index.html (body)" region="body"> <code-example path="displaying-data/src/index.html" linenums="false" header="src/index.html (body)" region="body">
</code-example> </code-example>
@ -135,7 +135,7 @@ In either style, the template data bindings have the same access to the componen
<div class="alert is-helpful"> <div class="alert is-helpful">
By default, the Angular CLI generates components with a template file. You can override that with: By default, the Angular CLI command [`ng generate component`](cli/generate) generates components with a template file. You can override that with:
<code-example hideCopy language="sh" class="code-shell"> <code-example hideCopy language="sh" class="code-shell">
ng generate component hero -it ng generate component hero -it
@ -164,7 +164,7 @@ This app uses more terse "variable assignment" style simply for brevity.
To display a list of heroes, begin by adding an array of hero names to the component and redefine `myHero` to be the first name in the array. To display a list of heroes, begin by adding an array of hero names to the component and redefine `myHero` to be the first name in the array.
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (class)" region="class"> <code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" header="src/app/app.component.ts (class)" region="class">
</code-example> </code-example>
@ -174,7 +174,7 @@ Now use the Angular `ngFor` directive in the template to display
each item in the `heroes` list. each item in the `heroes` list.
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (template)" region="template"> <code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" header="src/app/app.component.ts (template)" region="template">
</code-example> </code-example>
@ -185,7 +185,7 @@ in the `<li>` element is the Angular "repeater" directive.
It marks that `<li>` element (and its children) as the "repeater template": It marks that `<li>` element (and its children) as the "repeater template":
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (li)" region="li"> <code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" header="src/app/app.component.ts (li)" region="li">
</code-example> </code-example>
@ -252,7 +252,7 @@ of hero names into an array of `Hero` objects. For that you'll need a `Hero` cla
With the following code: With the following code:
<code-example path="displaying-data/src/app/hero.ts" linenums="false" title="src/app/hero.ts"> <code-example path="displaying-data/src/app/hero.ts" linenums="false" header="src/app/hero.ts">
</code-example> </code-example>
@ -266,7 +266,7 @@ The declaration of the constructor parameters takes advantage of a TypeScript sh
Consider the first parameter: Consider the first parameter:
<code-example path="displaying-data/src/app/hero.ts" linenums="false" title="src/app/hero.ts (id)" region="id"> <code-example path="displaying-data/src/app/hero.ts" linenums="false" header="src/app/hero.ts (id)" region="id">
</code-example> </code-example>
@ -286,7 +286,7 @@ After importing the `Hero` class, the `AppComponent.heroes` property can return
of `Hero` objects: of `Hero` objects:
<code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" title="src/app/app.component.ts (heroes)" region="heroes"> <code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" header="src/app/app.component.ts (heroes)" region="heroes">
</code-example> </code-example>
@ -297,7 +297,7 @@ At the moment it displays the hero's `id` and `name`.
Fix that to display only the hero's `name` property. Fix that to display only the hero's `name` property.
<code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" title="src/app/app.component.ts (template)" region="template"> <code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" header="src/app/app.component.ts (template)" region="template">
</code-example> </code-example>
@ -317,7 +317,7 @@ The Angular `ngIf` directive inserts or removes an element based on a _truthy/fa
To see it in action, add the following paragraph at the bottom of the template: To see it in action, add the following paragraph at the bottom of the template:
<code-example path="displaying-data/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts (message)" region="message"> <code-example path="displaying-data/src/app/app.component.ts" linenums="false" header="src/app/app.component.ts (message)" region="message">
</code-example> </code-example>
@ -357,7 +357,7 @@ big chunks of HTML with many data bindings.
Try it out. Because the array has four items, the message should appear. Try it out. Because the array has four items, the message should appear.
Go back into <code>app.component.ts"</code> and delete or comment out one of the elements from the hero array. Go back into <code>app.component.ts</code> and delete or comment out one of the elements from the hero array.
The browser should refresh automatically and the message should disappear. The browser should refresh automatically and the message should disappear.
@ -375,19 +375,19 @@ Here's the final code:
<code-tabs> <code-tabs>
<code-pane title="src/app/app.component.ts" path="displaying-data/src/app/app.component.ts" region="final"> <code-pane header="src/app/app.component.ts" path="displaying-data/src/app/app.component.ts" region="final">
</code-pane> </code-pane>
<code-pane title="src/app/hero.ts" path="displaying-data/src/app/hero.ts"> <code-pane header="src/app/hero.ts" path="displaying-data/src/app/hero.ts">
</code-pane> </code-pane>
<code-pane title="src/app/app.module.ts" path="displaying-data/src/app/app.module.ts"> <code-pane header="src/app/app.module.ts" path="displaying-data/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="main.ts" path="displaying-data/src/main.ts"> <code-pane header="main.ts" path="displaying-data/src/main.ts">
</code-pane> </code-pane>

View File

@ -310,22 +310,22 @@ _This_ "Authors Doc Style Guide" has its own sample application, located in the
The following _code-example_ displays the sample's `app.module.ts`. The following _code-example_ displays the sample's `app.module.ts`.
<code-example path="docs-style-guide/src/app/app.module.ts" title="src/app/app.module.ts"></code-example> <code-example path="docs-style-guide/src/app/app.module.ts" header="src/app/app.module.ts"></code-example>
Here's the brief markup that produced that lengthy snippet: Here's the brief markup that produced that lengthy snippet:
```html ```html
<code-example <code-example
path="docs-style-guide/src/app/app.module.ts" path="docs-style-guide/src/app/app.module.ts"
title="src/app/app.module.ts"> header="src/app/app.module.ts">
</code-example> </code-example>
``` ```
You identified the snippet's source file by setting the `path` attribute to sample folder's location _within_ `content/examples`. You identified the snippet's source file by setting the `path` attribute to sample folder's location _within_ `content/examples`.
In this example, that path is `docs-style-guide/src/app/app.module.ts`. In this example, that path is `docs-style-guide/src/app/app.module.ts`.
You added a header to tell the reader where to find the file by setting the `title` attribute. You added a header to tell the reader where to find the file by setting the `header` attribute.
Following convention, you set the `title` attribute to the file's location within the sample's root folder. Following convention, you set the `header` attribute to the file's location within the sample's root folder.
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -343,7 +343,7 @@ If you want to include an ignored code file in your project and display it in a
The preferred way to un-ignore a file is to update the `content/examples/.gitignore` like this: The preferred way to un-ignore a file is to update the `content/examples/.gitignore` like this:
<code-example title="content/examples/.gitignore"> <code-example header="content/examples/.gitignore">
# my-guide # my-guide
!my-guide/src/something.js !my-guide/src/something.js
!my-guide/more-javascript*.js !my-guide/more-javascript*.js
@ -357,7 +357,7 @@ You control the _code-example_ output by setting one or more of its attributes:
* `path`- the path to the file in the `content/examples` folder. * `path`- the path to the file in the `content/examples` folder.
* `title`- the header of the code listing. * `header`- the header of the code listing.
* `region`- displays the source file fragment with that region name; regions are identified by _docregion_ markup in the source file, as explained [below](#region "Displaying a code fragment"). * `region`- displays the source file fragment with that region name; regions are identified by _docregion_ markup in the source file, as explained [below](#region "Displaying a code fragment").
@ -395,7 +395,7 @@ A couple of observations:
1. The `region` value, `"class"`, is the name of the `#docregion` in the source file. Confirm that by looking at `content/examples/docs-style-guide/src/app/app.module.ts` 1. The `region` value, `"class"`, is the name of the `#docregion` in the source file. Confirm that by looking at `content/examples/docs-style-guide/src/app/app.module.ts`
1. Omitting the `title` is fine when the source of the fragment is obvious. We just said that this is a fragment of the `app.module.ts` file which was displayed immediately above, in full, with a header. 1. Omitting the `header` is fine when the source of the fragment is obvious. We just said that this is a fragment of the `app.module.ts` file which was displayed immediately above, in full, with a header.
There's no need to repeat the header. There's no need to repeat the header.
1. The line numbers disappeared. By default, the doc viewer omits line numbers when there are fewer than 10 lines of code; it adds line numbers after that. You can turn line numbers on or off explicitly by setting the `linenums` attribute. 1. The line numbers disappeared. By default, the doc viewer omits line numbers when there are fewer than 10 lines of code; it adds line numbers after that. You can turn line numbers on or off explicitly by setting the `linenums` attribute.
@ -415,11 +415,11 @@ Here's the markup for an "avoid" example in the
<code-example <code-example
path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts" path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts"
region="example" region="example"
title="app/heroes/hero-button/hero-button.component.ts"> header="app/heroes/hero-button/hero-button.component.ts">
</code-example> </code-example>
``` ```
<code-example path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/hero-button/hero-button.component.ts"> <code-example path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" header="app/heroes/hero-button/hero-button.component.ts">
</code-example> </code-example>
{@a code-tabs} {@a code-tabs}
@ -434,29 +434,29 @@ Code tabs display code much like _code examples_ do. The added advantage is tha
#### Code-pane attributes #### Code-pane attributes
* `path` - a file in the content/examples folder * `path` - a file in the content/examples folder
* `title` - seen in the header of a tab * `header` - seen in the header of a tab
* `linenums` - overrides the `linenums` property at the `code-tabs` level for this particular pane. The value can be `true`, `false` or a number indicating the starting line number. If not specified, line numbers are enabled only when the number of lines of code are greater than 10. * `linenums` - overrides the `linenums` property at the `code-tabs` level for this particular pane. The value can be `true`, `false` or a number indicating the starting line number. If not specified, line numbers are enabled only when the number of lines of code are greater than 10.
The next example displays multiple code tabs, each with its own title. The next example displays multiple code tabs, each with its own header.
It demonstrates control over display of line numbers at both the `<code-tabs>` and `<code-pane>` levels. It demonstrates control over display of line numbers at both the `<code-tabs>` and `<code-pane>` levels.
<code-tabs linenums="false"> <code-tabs linenums="false">
<code-pane <code-pane
title="app.component.html" header="app.component.html"
path="docs-style-guide/src/app/app.component.html"> path="docs-style-guide/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="app.component.ts" header="app.component.ts"
path="docs-style-guide/src/app/app.component.ts" path="docs-style-guide/src/app/app.component.ts"
linenums="true"> linenums="true">
</code-pane> </code-pane>
<code-pane <code-pane
title="app.component.css (heroes)" header="app.component.css (heroes)"
path="docs-style-guide/src/app/app.component.css" path="docs-style-guide/src/app/app.component.css"
region="heroes"> region="heroes">
</code-pane> </code-pane>
<code-pane <code-pane
title="package.json (scripts)" header="package.json (scripts)"
path="docs-style-guide/package.1.json"> path="docs-style-guide/package.1.json">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -469,21 +469,21 @@ The `linenums` attribute in the second pane restores line numbering for _itself
```html ```html
<code-tabs linenums="false"> <code-tabs linenums="false">
<code-pane <code-pane
title="app.component.html" header="app.component.html"
path="docs-style-guide/src/app/app.component.html"> path="docs-style-guide/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane <code-pane
title="app.component.ts" header="app.component.ts"
path="docs-style-guide/src/app/app.component.ts" path="docs-style-guide/src/app/app.component.ts"
linenums="true"> linenums="true">
</code-pane> </code-pane>
<code-pane <code-pane
title="app.component.css (heroes)" header="app.component.css (heroes)"
path="docs-style-guide/src/app/app.component.css" path="docs-style-guide/src/app/app.component.css"
region="heroes"> region="heroes">
</code-pane> </code-pane>
<code-pane <code-pane
title="package.json (scripts)" header="package.json (scripts)"
path="docs-style-guide/package.1.json"> path="docs-style-guide/package.1.json">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -548,7 +548,7 @@ The `src/main.ts` is a simple example of a file with a single _#docregion_ at th
<code-example <code-example
path="docs-style-guide/src/main.ts" path="docs-style-guide/src/main.ts"
title="src/main.ts"></code-example> header="src/main.ts"></code-example>
</div> </div>
@ -622,12 +622,12 @@ Here's are the two corresponding code snippets displayed side-by-side.
<code-tabs> <code-tabs>
<code-pane <code-pane
title="app.component.ts (class)" header="app.component.ts (class)"
path="docs-style-guide/src/app/app.component.ts" path="docs-style-guide/src/app/app.component.ts"
region="class"> region="class">
</code-pane> </code-pane>
<code-pane <code-pane
title="app.component.ts (class-skeleton)" header="app.component.ts (class-skeleton)"
path="docs-style-guide/src/app/app.component.ts" path="docs-style-guide/src/app/app.component.ts"
region="class-skeleton"> region="class-skeleton">
</code-pane> </code-pane>
@ -660,12 +660,12 @@ Here's an example that excerpts certain scripts from `package.json` into a parti
<code-example <code-example
path="docs-style-guide/package.1.json" path="docs-style-guide/package.1.json"
title="package.json (selected scripts)"></code-example> header="package.json (selected scripts)"></code-example>
```html ```html
<code-example <code-example
path="docs-style-guide/package.1.json" path="docs-style-guide/package.1.json"
title="package.json (selected scripts)"></code-example> header="package.json (selected scripts)"></code-example>
``` ```
#### Partial file naming #### Partial file naming
@ -689,7 +689,7 @@ Remember to exclude these files from stackblitz by listing them in the `stackbli
<code-example <code-example
path="docs-style-guide/stackblitz.json" path="docs-style-guide/stackblitz.json"
title="stackblitz.json"></code-example> header="stackblitz.json"></code-example>
{@a live-examples} {@a live-examples}
## Live examples ## Live examples

View File

@ -35,7 +35,7 @@ The ad banner uses a helper directive called `AdDirective` to
mark valid insertion points in the template. mark valid insertion points in the template.
<code-example path="dynamic-component-loader/src/app/ad.directive.ts" title="src/app/ad.directive.ts" linenums="false"> <code-example path="dynamic-component-loader/src/app/ad.directive.ts" header="src/app/ad.directive.ts" linenums="false">
</code-example> </code-example>
@ -62,7 +62,7 @@ To apply the `AdDirective`, recall the selector from `ad.directive.ts`,
where to dynamically load components. where to dynamically load components.
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="ad-host" title="src/app/ad-banner.component.ts (template)" linenums="false"> <code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="ad-host" header="src/app/ad-banner.component.ts (template)" linenums="false">
</code-example> </code-example>
@ -91,7 +91,7 @@ With its `getAds()` method, `AdBannerComponent` cycles through the array of `AdI
and loads a new component every 3 seconds by calling `loadComponent()`. and loads a new component every 3 seconds by calling `loadComponent()`.
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="class" title="src/app/ad-banner.component.ts (excerpt)" linenums="false"> <code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="class" header="src/app/ad-banner.component.ts (excerpt)" linenums="false">
</code-example> </code-example>
@ -150,7 +150,7 @@ dynamically loaded components since they load at runtime.
To ensure that the compiler still generates a factory, To ensure that the compiler still generates a factory,
add dynamically loaded components to the `NgModule`'s `entryComponents` array: add dynamically loaded components to the `NgModule`'s `entryComponents` array:
<code-example path="dynamic-component-loader/src/app/app.module.ts" region="entry-components" title="src/app/app.module.ts (entry components)" linenums="false"> <code-example path="dynamic-component-loader/src/app/app.module.ts" region="entry-components" header="src/app/app.module.ts (entry components)" linenums="false">
</code-example> </code-example>
@ -169,15 +169,15 @@ Here are two sample components and the `AdComponent` interface for reference:
<code-tabs> <code-tabs>
<code-pane title="hero-job-ad.component.ts" path="dynamic-component-loader/src/app/hero-job-ad.component.ts"> <code-pane header="hero-job-ad.component.ts" path="dynamic-component-loader/src/app/hero-job-ad.component.ts">
</code-pane> </code-pane>
<code-pane title="hero-profile.component.ts" path="dynamic-component-loader/src/app/hero-profile.component.ts"> <code-pane header="hero-profile.component.ts" path="dynamic-component-loader/src/app/hero-profile.component.ts">
</code-pane> </code-pane>
<code-pane title="ad.component.ts" path="dynamic-component-loader/src/app/ad.component.ts"> <code-pane header="ad.component.ts" path="dynamic-component-loader/src/app/ad.component.ts">
</code-pane> </code-pane>

View File

@ -40,11 +40,11 @@ Bootstrap the `AppModule` in `main.ts`.
<code-tabs> <code-tabs>
<code-pane title="app.module.ts" path="dynamic-form/src/app/app.module.ts"> <code-pane header="app.module.ts" path="dynamic-form/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="main.ts" path="dynamic-form/src/main.ts"> <code-pane header="main.ts" path="dynamic-form/src/main.ts">
</code-pane> </code-pane>
@ -62,7 +62,7 @@ The _question_ is the most fundamental object in the model.
The following `QuestionBase` is a fundamental question class. The following `QuestionBase` is a fundamental question class.
<code-example path="dynamic-form/src/app/question-base.ts" title="src/app/question-base.ts"> <code-example path="dynamic-form/src/app/question-base.ts" header="src/app/question-base.ts">
</code-example> </code-example>
@ -77,7 +77,7 @@ appropriate controls dynamically.
via the `type` property. via the `type` property.
<code-example path="dynamic-form/src/app/question-textbox.ts" title="src/app/question-textbox.ts" linenums="false"> <code-example path="dynamic-form/src/app/question-textbox.ts" header="src/app/question-textbox.ts" linenums="false">
</code-example> </code-example>
@ -86,7 +86,7 @@ via the `type` property.
`DropdownQuestion` presents a list of choices in a select box. `DropdownQuestion` presents a list of choices in a select box.
<code-example path="dynamic-form/src/app/question-dropdown.ts" title="src/app/question-dropdown.ts" linenums="false"> <code-example path="dynamic-form/src/app/question-dropdown.ts" header="src/app/question-dropdown.ts" linenums="false">
</code-example> </code-example>
@ -97,7 +97,7 @@ In a nutshell, the form group consumes the metadata from the question model and
allows you to specify default values and validation rules. allows you to specify default values and validation rules.
<code-example path="dynamic-form/src/app/question-control.service.ts" title="src/app/question-control.service.ts" linenums="false"> <code-example path="dynamic-form/src/app/question-control.service.ts" header="src/app/question-control.service.ts" linenums="false">
</code-example> </code-example>
@ -112,11 +112,11 @@ to create components to represent the dynamic form.
<code-tabs> <code-tabs>
<code-pane title="dynamic-form.component.html" path="dynamic-form/src/app/dynamic-form.component.html"> <code-pane header="dynamic-form.component.html" path="dynamic-form/src/app/dynamic-form.component.html">
</code-pane> </code-pane>
<code-pane title="dynamic-form.component.ts" path="dynamic-form/src/app/dynamic-form.component.ts"> <code-pane header="dynamic-form.component.ts" path="dynamic-form/src/app/dynamic-form.component.ts">
</code-pane> </code-pane>
@ -132,11 +132,11 @@ question based on values in the data-bound question object.
<code-tabs> <code-tabs>
<code-pane title="dynamic-form-question.component.html" path="dynamic-form/src/app/dynamic-form-question.component.html"> <code-pane header="dynamic-form-question.component.html" path="dynamic-form/src/app/dynamic-form-question.component.html">
</code-pane> </code-pane>
<code-pane title="dynamic-form-question.component.ts" path="dynamic-form/src/app/dynamic-form-question.component.ts"> <code-pane header="dynamic-form-question.component.ts" path="dynamic-form/src/app/dynamic-form-question.component.ts">
</code-pane> </code-pane>
@ -169,7 +169,7 @@ directly since you imported `ReactiveFormsModule` from `AppModule`.
and removing objects from the `questions` array. and removing objects from the `questions` array.
<code-example path="dynamic-form/src/app/question.service.ts" title="src/app/question.service.ts"> <code-example path="dynamic-form/src/app/question.service.ts" header="src/app/question.service.ts">
</code-example> </code-example>
@ -178,7 +178,7 @@ directly since you imported `ReactiveFormsModule` from `AppModule`.
Finally, display an instance of the form in the `AppComponent` shell. Finally, display an instance of the form in the `AppComponent` shell.
<code-example path="dynamic-form/src/app/app.component.ts" title="app.component.ts"> <code-example path="dynamic-form/src/app/app.component.ts" header="app.component.ts">
</code-example> </code-example>

View File

@ -119,7 +119,7 @@ The recently-developed [custom elements](https://developer.mozilla.org/en-US/doc
In browsers that support Custom Elements natively, the specification requires developers use ES2015 classes to define Custom Elements - developers can opt-in to this by setting the `target: "es2015"` property in their project's `tsconfig.json`. As Custom Element and ES2015 support may not be available in all browsers, developers can instead choose to use a polyfill to support older browsers and ES5 code. In browsers that support Custom Elements natively, the specification requires developers use ES2015 classes to define Custom Elements - developers can opt-in to this by setting the `target: "es2015"` property in their project's `tsconfig.json`. As Custom Element and ES2015 support may not be available in all browsers, developers can instead choose to use a polyfill to support older browsers and ES5 code.
Use the [Angular CLI](https://cli.angular.io/) to automatically set up your project with the correct polyfill: `ng add @angular/elements --name=*your_project_name*`. Use the [Angular CLI](cli) to automatically set up your project with the correct polyfill: `ng add @angular/elements --name=*your_project_name*`.
- For more information about polyfills, see [polyfill documentation](https://www.webcomponents.org/polyfills). - For more information about polyfills, see [polyfill documentation](https://www.webcomponents.org/polyfills).
- For more information about Angular browser support, see [Browser Support](guide/browser-support). - For more information about Angular browser support, see [Browser Support](guide/browser-support).
@ -142,19 +142,19 @@ For comparison, the demo shows both methods. One button adds the popup using the
<code-tabs> <code-tabs>
<code-pane title="popup.component.ts" path="elements/src/app/popup.component.ts"> <code-pane header="popup.component.ts" path="elements/src/app/popup.component.ts">
</code-pane> </code-pane>
<code-pane title="popup.service.ts" path="elements/src/app/popup.service.ts"> <code-pane header="popup.service.ts" path="elements/src/app/popup.service.ts">
</code-pane> </code-pane>
<code-pane title="app.module.ts" path="elements/src/app/app.module.ts"> <code-pane header="app.module.ts" path="elements/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="app.component.ts" path="elements/src/app/app.component.ts"> <code-pane header="app.component.ts" path="elements/src/app/app.component.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>

View File

@ -33,7 +33,7 @@ pipes that it shares.
## How to make a feature module ## How to make a feature module
Assuming you already have a CLI generated app, create a feature Assuming you already have an app that you created with the [Angular CLI](cli), create a feature
module using the CLI by entering the following command in the module using the CLI by entering the following command in the
root project directory. Replace `CustomerDashboard` with the root project directory. Replace `CustomerDashboard` with the
name of your module. You can omit the "Module" suffix from the name because the CLI appends it: name of your module. You can omit the "Module" suffix from the name because the CLI appends it:
@ -72,7 +72,7 @@ ng generate component customer-dashboard/CustomerDashboard
This generates a folder for the new component within the customer-dashboard folder and updates the feature module with the `CustomerDashboardComponent` info: This generates a folder for the new component within the customer-dashboard folder and updates the feature module with the `CustomerDashboardComponent` info:
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="customer-dashboard-component" title="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false"> <code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="customer-dashboard-component" header="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false">
</code-example> </code-example>
@ -83,7 +83,7 @@ The `CustomerDashboardComponent` is now in the JavaScript import list at the top
To incorporate the feature module into your app, you have to let the root module, `app.module.ts`, know about it. Notice the `CustomerDashboardModule` export at the bottom of `customer-dashboard.module.ts`. This exposes it so that other modules can get to it. To import it into the `AppModule`, add it to the imports in `app.module.ts` and to the `imports` array: To incorporate the feature module into your app, you have to let the root module, `app.module.ts`, know about it. Notice the `CustomerDashboardModule` export at the bottom of `customer-dashboard.module.ts`. This exposes it so that other modules can get to it. To import it into the `AppModule`, add it to the imports in `app.module.ts` and to the `imports` array:
<code-example path="feature-modules/src/app/app.module.ts" region="app-module" title="src/app/app.module.ts" linenums="false"> <code-example path="feature-modules/src/app/app.module.ts" region="app-module" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
@ -94,20 +94,20 @@ Now the `AppModule` knows about the feature module. If you were to add any servi
When the CLI generated the `CustomerDashboardComponent` for the feature module, it included a template, `customer-dashboard.component.html`, with the following markup: When the CLI generated the `CustomerDashboardComponent` for the feature module, it included a template, `customer-dashboard.component.html`, with the following markup:
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" region="feature-template" title="src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" linenums="false"> <code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" region="feature-template" header="src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" linenums="false">
</code-example> </code-example>
To see this HTML in the `AppComponent`, you first have to export the `CustomerDashboardComponent` in the `CustomerDashboardModule`. In `customer-dashboard.module.ts`, just beneath the `declarations` array, add an `exports` array containing `CustomerDashboardModule`: To see this HTML in the `AppComponent`, you first have to export the `CustomerDashboardComponent` in the `CustomerDashboardModule`. In `customer-dashboard.module.ts`, just beneath the `declarations` array, add an `exports` array containing `CustomerDashboardComponent`:
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="component-exports" title="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false"> <code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="component-exports" header="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false">
</code-example> </code-example>
Next, in the `AppComponent`, `app.component.html`, add the tag `<app-customer-dashboard>`: Next, in the `AppComponent`, `app.component.html`, add the tag `<app-customer-dashboard>`:
<code-example path="feature-modules/src/app/app.component.html" region="app-component-template" title="src/app/app.component.html" linenums="false"> <code-example path="feature-modules/src/app/app.component.html" region="app-component-template" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>

View File

@ -1,67 +1,110 @@
# Workspace and project file structure # Workspace and project file structure
An Angular CLI project is the foundation for both quick experiments and enterprise solutions. The CLI command `ng new` creates an Angular workspace in your file system that is the root for new projects, which can be apps and libraries. You develop apps in the context of an Angular [workspace](guide/glossary#workspace). A workspace contains the files for one or more [projects](guide/glossary#project). A project is the set of files that comprise a standalone app, a library, or a set of end-to-end (e2e) tests.
## Workspaces and project files The Angular CLI command `ng new <project_name>` gets you started.
When you run this command, the CLI installs the necessary Angular npm packages and other dependencies in a new workspace, with a root folder named *project_name*.
It also creates the following workspace and starter project files:
Angular 6 introduced the [workspace](guide/glossary#workspace) directory structure for Angular [projects](guide/glossary#project). A project can be a standalone *application* or a *library*, and a workspace can contain multiple applications, as well as libraries that can be used in any of the apps. * An initial skeleton app project, also called *project_name* (in the `src/` subfolder).
* An end-to-end test project (in the `e2e/` subfolder).
* Related configuration files.
The CLI command `ng new my-workspace` creates a workspace folder and generates a new app skeleton in an `app` folder within that workspace. The initial app project contains a simple Welcome app, ready to run.
Within the `app/` folder, a `src/` subfolder contains the logic, data, and assets.
A newly generated `app/` folder contains the source files for a root module, with a root component and template.
The `app/` folder also contains project-specific configuration files, end-to-end tests, and the Angular system modules. ## Workspace files
``` The top level of the workspace contains a number of workspace-wide configuration files.
my-workspace/
app/
e2e/
src/
node_modules/
src/
```
When this workspace file structure is in place, you can use the `ng generate` command on the command line to add functionality and data to the initial app. | WORKSPACE CONFIG FILES | PURPOSE |
| :--------------------- | :------------------------------------------|
| `.editorconfig` | Configuration for code editors. See [EditorConfig](https://editorconfig.org/). |
| `.gitignore` | Specifies intentionally untracked files that [Git](https://git-scm.com/) should ignore. |
| `angular.json` | CLI configuration for all projects in the workspace, including configuration options for build, serve, and test tools that the CLI uses, such as [Karma](https://karma-runner.github.io/) and [Protractor](http://www.protractortest.org/). |
| `node_modules` | Provides [npm packages](guide/npm-packages) to the entire workspace. |
| `package.json` | Lists package dependencies. See [npm documentation](https://docs.npmjs.com/files/package.json) for the specific format and contents of this file.|
| `tsconfig.app.json` | Default [TypeScript](https://www.typescriptlang.org/) configuration for apps in the workspace. |
| `tsconfig.spec.json` | Default TypeScript configuration for e2e test apps in the workspace. |
| `tslint.json` | Default [TSLint](https://palantir.github.io/tslint/) configuration for apps in the workspace. |
| `README.md` | Introductory documentation. |
| `package-lock.json` | Provides version information for all packages installed into `node_modules` by the npm client. See [npm documentation](https://docs.npmjs.com/files/package-lock.json) for details. If you use the yarn client, this file will be [yarn.lock](https://yarnpkg.com/lang/en/docs/yarn-lock/) instead. |
<div class="alert-is-helpful> All projects within a workspace share this configuration context.
Project-specific [TypeScript](https://www.typescriptlang.org/) configuration files inherit from the workspace-wide `tsconfig.*.json`, and app-specific [TSLint](https://palantir.github.io/tslint/) configuration files inherit from the workspace-wide `tslint.json`.
### Default app project files
The CLI command `ng new my-app` creates a workspace folder named "my-app" and generates a new app skeleton.
This initial app is the *default app* for CLI commands (unless you change the default after creating additional apps).
A newly generated app contains the source files for a root module, with a root component and template.
When the workspace file structure is in place, you can use the `ng generate` command on the command line to add functionality and data to the initial app.
<div class="alert is-helpful>
Besides using the CLI on the command line, You can also use an interactive development environment like [Angular Console](https://angular.console.com), or manipulate files directly in the app's source folder and configuration files. Besides using the CLI on the command line, You can also use an interactive development environment like [Angular Console](https://angular.console.com), or manipulate files directly in the app's source folder and configuration files.
</div> </div>
{@a global-config} The `src/` subfolder contains the source files (app logic, data, and assets), along with configuration files for the initial app.
Workspace-wide `node_modules` dependencies are visible to this project.
## Global workspace configuration | APP SOURCE & CONFIG FILES | PURPOSE |
| :--------------------- | :------------------------------------------|
| `app/` | Contains the component files in which your app logic and data are defined. See details in [App source folder](#app-src) below. |
| `assets/` | Contains image files and other asset files to be copied as-is when you build your application. |
| `environments/` | Contains build configuration options for particular target environments. By default there is an unnamed standard development environment and a production ("prod") environment. You can define additional target environment configurations. |
| `browserlist` | Configures sharing of target browsers and Node.js versions among various front-end tools. See [Browserlist on GitHub](https://github.com/browserslist/browserslist) for more information. |
| `favicon.ico` | An icon to use for this app in the bookmark bar. |
| `index.html` | The main HTML page that is served when someone visits your site. The CLI automatically adds all JavaScript and CSS files when building your app, so you typically don't need to add any `<script>` or` <link>` tags here manually. |
| `main.ts` | The main entry point for your app. Compiles the application with the [JIT compiler](https://angular.io/guide/glossary#jit) and bootstraps the application's root module (AppModule) to run in the browser. You can also use the [AOT compiler](https://angular.io/guide/aot-compiler) without changing any code by appending the `--aot` flag to the CLI `build` and `serve` commands. |
| `polyfills.ts` | Provides polyfill scripts for browser support. |
| `styles.sass` | Lists CSS files that supply styles for a project. The extension reflects the style preprocessor you have configured for the project. |
| `test.ts` | The main entry point for your unit tests, with some Angular-specific configuration. You don't typically need to edit this file. |
| `tsconfig.app.json` | Inherits from the workspace-wide `tsconfig.json` file. |
| `tsconfig.spec.json` | Inherits from the workspace-wide `tsconfig.json` file. |
| `tslint.json` | Inherits from the workspace-wide `tslint.json` file. |
A workspace can contain additional apps and libraries, each with its own root folder under `projects/`. ### Default app project e2e files
``` An `e2e/` subfolder contains configuration and source files for a set of end-to-end tests that correspond to the initial app.
my-workspace/ Workspace-wide `node_modules` dependencies are visible to this project.
app/
projects/
my-app/
helpful-library/
my-other-app/
angular.json
```
At the top level of the workspace, the CLI configuration file, `angular.json`, let you set defaults for all projects in the workspace. You can configure a workspace, for example, such that all projects in it have global access to libraries, scripts, and CSS styles. (For more in this, see [Configuring global access](#global-access).)
You can also use `ng generate app` to create new Angular apps in the workspace, and use the `ng add` command to add libraries. <code-example language="none" linenums="false">
If you add libraries or generate more apps within a workspace, a `projects/` folder is created to contain the new libraries or apps. my-app/
Additional apps and library subfolders have the same file structure as the initial app. e2e/ (end-to-end test app for my-app)
src/ (app source files)
protractor.conf.js (test-tool config)
tsconfig.e2e.json (TypeScript config inherits from workspace tsconfig.json)
</code-example>
All of the projects within a workspace share a CLI configuration context, controlled by the `angular.json` configuration file at the root level of the workspace. ### Project folders for additional apps and libraries
| GLOBAL CONFIG FILES | PURPOSE | When you generate new projects in a workspace,
| :------------- | :------------------------------------------| the CLI creates a new *workspace*`/projects` folder, and adds the generated files there.
| `angular.json` | Sets defaults for the CLI and configuration options for build, serve, and test tools that the CLI uses, such as [Karma](https://karma-runner.github.io/) and [Protractor](http://www.protractortest.org/). For complete details, see *CLI Reference (link TBD)*. |
When you generate an app (`ng generate application my-other-app`), the CLI adds folders under `projects/` for both the app and its corresponding end-to-end tests. Newly generated libraries are also added under `projects/`.
<code-example language="none" linenums="false">
my-app/
...
projects/ (additional apps and libs)
my-other-app/ (a second app)
src/
(config files)
my-other-app-e2e/ (corresponding test app)
src/
(config files)
my-lib/ (a generated library)
(config files)
</code-example>
{@a app-src}
## App source folder ## App source folder
The app-root source folder contains your app's logic and data. Angular components, templates, styles, images, and anything else your app needs go here. Files outside of the source folder support testing and building your app. Inside the `src/` folder, the `app/` folder contains your app's logic and data. Angular components, templates, and styles go here. An `assets/` subfolder contains images and anything else your app needs. Files at the top level of `src/` support testing and running your app.
``` <code-example language="none" linenums="false">
src/ src/
app/ app/
app.component.css app.component.css
@ -70,313 +113,14 @@ The app-root source folder contains your app's logic and data. Angular component
app.component.ts app.component.ts
app.module.ts app.module.ts
assets/... assets/...
favicon.ico ...
index.html </code-example>
main.ts
test.ts
```
| APP SOURCE FILES | PURPOSE | | APP SOURCE FILES | PURPOSE |
| :----------------------------- | :------------------------------------------| | :-------------------------- | :------------------------------------------|
| `app/app.component.ts` | Defines the logic for the app's root component, named AppComponent. The view associated with this root component becomes the root of the [view hierarchy](guide/glossary#view-hierarchy) as you add components and services to your app. | | `app/app.component.ts` | Defines the logic for the app's root component, named `AppComponent`. The view associated with this root component becomes the root of the [view hierarchy](guide/glossary#view-hierarchy) as you add components and services to your app. |
| `app/app.component.html` | Defines the HTML template associated with the root AppComponent. | | `app/app.component.html` | Defines the HTML template associated with the root `AppComponent`. |
| `app/app.component.css` | Defines the base CSS stylesheet for the root AppComponent. | | `app/app.component.css` | Defines the base CSS stylesheet for the root `AppComponent`. |
| `app/app.component.spec.ts` | Defines a unit test for the root AppComponent. | | `app/app.component.spec.ts` | Defines a unit test for the root `AppComponent`. |
| `app/app.module.ts` | Defines the root module, named AppModule, that tells Angular how to assemble the application. Initially declares only the AppComponent. As you add more components to the app, they must be declared here. | | `app/app.module.ts` | Defines the root module, named `AppModule`, that tells Angular how to assemble the application. Initially declares only the `AppComponent`. As you add more components to the app, they must be declared here. |
| `assets/*` | Contains image files and other asset files to be copied as-is when you build your application. | | `assets/*` | Contains image files and other asset files to be copied as-is when you build your application. |
| PROJECT-LEVEL FILES | PURPOSE |
| :------------------------ | :------------------------------------------|
| `favicon.ico` | An icon to use for this app in the bookmark bar. |
| `index.html` | The main HTML page that is served when someone visits your site. The CLI automatically adds all JavaScript and CSS files when building your app, so you typically don't need to add any `<script>` or` <link>` tags here manually. |
| `main.ts` | The main entry point for your app. Compiles the application with the [JIT compiler](https://angular.io/guide/glossary#jit) and bootstraps the application's root module (AppModule) to run in the browser. You can also use the [AOT compiler](https://angular.io/guide/aot-compiler) without changing any code by appending the `--aot` flag to the CLI `build` and `serve` commands. |
| `test.ts` | The main entry point for your unit tests, with some Angular-specific configuration. You don't typically need to edit this file. |
## App support file structure
Additional files in a project's root folder help you build, test, maintain, document, and deploy the app. These files go in the app root folder next to `src/`.
```
workspace_root/
my-app/
e2e/
src/
app.e2e-spec.ts
app.po.ts
tsconfig.e2e.json
protractor.conf.js
node_modules/...
src/...
```
| FOLDERS | PURPOSE |
| :---------------- | :-------------------------------------------- |
| `e2e/` | This folder contains end-to-end tests for the app. This is a separate app that tests your main app. The folder and its contents are generated automatically when you create a new app with the CLI `new` or `generate` command. |
| `node_modules/` | Node.js creates this folder and puts all third party modules listed in `package.json` in it. *when? doesn't ng new create it?* |
### Project-level configuration
Each project uses the CLI configuration at the workspace root-level `angular.json` file.
Additional project-specific configuration files are found at the project root level of each app or library.
```
my-workspace/
app/
.editorconfig
.gitignore
package.json
README.md
tsconfig.json
tsconfig.test.json
tslint.json
projects/
helpful-library/
my-other-app/
.editorconfig
.gitignore
package.json
README.md
tsconfig.json
tsconfig.test.json
tslint.json
angular.json
```
| CONFIGURATION FILES | PURPOSE |
| :------------------ | :-------------------------------------------- |
| `.editorconfig` | Simple configuration for your editor to make sure everyone who uses your project has the same basic configuration. Supported by most editors. See http://editorconfig.org for more information. |
| `.gitignore` | Git configuration to make sure autogenerated files are not committed to source control. |
| `package.json` | Configures the `npm` package manager, listing the third party packages your project uses. You can also add your own custom scripts here. |
| `README.md` | Basic documentation for your project, pre-filled with CLI command information. We recommend that you keep this updated so that anyone checking out the repo can build your app. |
| `tsconfig.json` | TypeScript compiler configuration, that an IDE such as [Visual Studio Code](https://code.visualstudio.com/) uses to give you helpful tooling. |
| `tslint.json` | Linting configuration for [TSLint](https://palantir.github.io/tslint/) together with [Codelyzer](http://codelyzer.com/), used when running the CLI `lint` command. Linting helps keep your code style consistent. |
{@a global-access}
## Configuring global access
The CLI configuration scope is global for a workspace.
You can make scripts, libraries, and styles available to all projects in the workspace by setting options in the `angular.json` file in the root workspace folder.
### Adding global scripts
You can configure your project to add JavaScript files to the global scope.
This is especially useful for legacy libraries or analytic snippets.
In the CLI configuration file, `angular.json`, add the associated script files to the `scripts` array.
The scripts are loaded exactly as if you had added them in a `<script>` tag inside `index.html`.
For example:
```
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"scripts": [
"src/global-script.js",
],
```
You can also rename the output from a script and lazy load it by using the object format in the "scripts" entry.
For example:
```
"scripts": [
"src/global-script.js",
{ "input": "src/lazy-script.js", "lazy": true },
{ "input": "src/pre-rename-script.js", "bundleName": "renamed-script" },
],
```
If you need to add scripts for unit tests, specify them the same way in the "test" target.
{@a add-lib}
### Adding a global library
Some JavaScript libraries need to be added to the global scope and loaded as if they were in a script tag.
Configure the CLI to do this using the "scripts" and "styles" options of the build target in the CLI configuration file, `angular.json`.
For example, to use the [Bootstrap 4](https://getbootstrap.com/docs/4.0/getting-started/introduction/)
library, first install the library and its dependencies using the `npm` package manager:
```
npm install jquery --save
npm install popper.js --save
npm install bootstrap --save
```
In the `angular.json` configuration file, add the associated script files to the "scripts" array:
```
"scripts": [
"node_modules/jquery/dist/jquery.slim.js",
"node_modules/popper.js/dist/umd/popper.js",
"node_modules/bootstrap/dist/js/bootstrap.js"
],
```
Add the Bootstrap CSS file to the "styles" array:
```
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.css",
"src/styles.css"
],
```
Run or restart `ng serve` to see Bootstrap 4 working in your app.
#### Using global libraries inside your app
Once you import a library using the "scripts" array in the configuration file,
you should *not* import it using an `import` statement in your TypeScript code
(such as `import * as $ from 'jquery';`).
If you do, you'll end up with two different copies of the library:
one imported as a global library, and one imported as a module.
This is especially bad for libraries with plugins, like JQuery,
because each copy will have different plugins.
Instead, download typings for your library (`npm install @types/jquery`) and follow the installation steps
given above in [Adding a global library](#add-lib).
This gives you access to the global variables exposed by that library.
{@a define-types}
#### Defining typings for global libraries
If the global library you need to use does not have global typings,
you can declare them manually as `any` in `src/typings.d.ts`. For example:
```
declare var libraryName: any;
```
Some scripts extend other libraries; for instance with JQuery plugins:
```
$('.test').myPlugin();
```
In this case, the installed `@types/jquery` doesn't include `myPlugin`,
so you need to add an *interface* in `src/typings.d.ts`.
For example:
```
interface JQuery {
myPlugin(options?: any): any;
}
```
If you fail to add the interface for the script-defined extension, your IDE shows an error:
```
[TS][Error] Property 'myPlugin' does not exist on type 'JQuery'
```
### Adding global styles and style preprocessors
Angular CLI supports CSS imports and all major CSS preprocessors:
* [Sass/Scss](http://sass-lang.com/)
* [Less](http://lesscss.org/)
* [Stylus](http://stylus-lang.com/)
Angular assumes CSS styles by default, but when you create a project with the
CLI `new` command, you can specify the `--style` option to use SASS or STYL styles.
```
> ng new sassyproject --style=sass
> ng new scss-project --style=scss
> ng new less-project --style=less
> ng new styl-project --style=styl
```
You can also set the default style for an existing project by configuring `@schematics/angular`,
the default schematic for the Angular CLI:
```
> ng config schematics.@schematics/angular:component.styleext scss
```
#### Style configuration
By default, the `styles.css` configuration file lists CSS files that supply global styles for a project.
If you are using another style type, there is a similar configuration file for global style files of that type,
with the extension for that style type, such as `styles.sass`.
You can add more global styles by configuring the build options in the `angular.json` configuration file.
List the style files in the "styles" section in your project's "build" target
The files are loaded exactly as if you had added them in a `<link>` tag inside `index.html`.
```
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"styles": [
"src/styles.css",
"src/more-styles.css",
],
...
```
If you need the styles in your unit tests, add them to the "styles" option in the "test" target configuration as well.
You can specify styles in an object format to rename the output and lazy load it:
```
"styles": [
"src/styles.css",
"src/more-styles.css",
{ "input": "src/lazy-style.scss", "lazy": true },
{ "input": "src/pre-rename-style.scss", "bundleName": "renamed-style" },
],
```
In Sass and Stylus you can make use of the `includePaths` functionality for both component and global styles,
which allows you to add extra base paths to be checked for imports.
To add paths, use the `stylePreprocessorOptions` build-target option:
```
"stylePreprocessorOptions": {
"includePaths": [
"src/style-paths"
]
},
```
You can then import files in the given folder (such as `src/style-paths/_variables.scss`)
anywhere in your project without the need for a relative path:
```
// src/app/app.component.scss
// A relative path works
@import '../style-paths/variables';
// But now this works as well
@import 'variables';
```
#### CSS preprocessor integration
To use a supported CSS preprocessor, add the URL for the preprocessor
to your component's `styleUrls` in the `@Component()` metadata.
For example:
```
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'app works!';
}
```
<div class="alert-is-helpful>
Style strings added directly to the `@Component() styles array must be written in CSS.
The CLI cannot apply a pre-processor to inline styles.
</div>

View File

@ -29,7 +29,7 @@ either a list of validation errors, which results in an INVALID status, or null,
You can then inspect the control's state by exporting `ngModel` to a local template variable. You can then inspect the control's state by exporting `ngModel` to a local template variable.
The following example exports `NgModel` into a variable called `name`: The following example exports `NgModel` into a variable called `name`:
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-with-error-msg" title="template/hero-form-template.component.html (name)" linenums="false"> <code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-with-error-msg" header="template/hero-form-template.component.html (name)" linenums="false">
</code-example> </code-example>
@ -92,7 +92,7 @@ built-in validators&mdash;this time, in function form. See below:
{@a reactive-component-class} {@a reactive-component-class}
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="form-group" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false"> <code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="form-group" header="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
</code-example> </code-example>
Note that: Note that:
@ -106,7 +106,7 @@ for the template.
If you look at the template for the name input again, it is fairly similar to the template-driven example. If you look at the template for the name input again, it is fairly similar to the template-driven example.
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="name-with-error-msg" title="reactive/hero-form-reactive.component.html (name with error msg)" linenums="false"> <code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="name-with-error-msg" header="reactive/hero-form-reactive.component.html (name with error msg)" linenums="false">
</code-example> </code-example>
Key takeaways: Key takeaways:
@ -125,7 +125,7 @@ Consider the `forbiddenNameValidator` function from previous
[examples](guide/form-validation#reactive-component-class) in [examples](guide/form-validation#reactive-component-class) in
this guide. Here's what the definition of that function looks like: this guide. Here's what the definition of that function looks like:
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="custom-validator" title="shared/forbidden-name.directive.ts (forbiddenNameValidator)" linenums="false"> <code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="custom-validator" header="shared/forbidden-name.directive.ts (forbiddenNameValidator)" linenums="false">
</code-example> </code-example>
The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name and returns a validator function. The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name and returns a validator function.
@ -148,7 +148,7 @@ at which point the form uses the last value emitted for validation.
In reactive forms, custom validators are fairly simple to add. All you have to do is pass the function directly In reactive forms, custom validators are fairly simple to add. All you have to do is pass the function directly
to the `FormControl`. to the `FormControl`.
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="custom-validator" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false"> <code-example path="form-validation/src/app/reactive/hero-form-reactive.component.1.ts" region="custom-validator" header="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
</code-example> </code-example>
### Adding to template-driven forms ### Adding to template-driven forms
@ -161,19 +161,19 @@ The corresponding `ForbiddenValidatorDirective` serves as a wrapper around the `
Angular recognizes the directive's role in the validation process because the directive registers itself Angular recognizes the directive's role in the validation process because the directive registers itself
with the `NG_VALIDATORS` provider, a provider with an extensible collection of validators. with the `NG_VALIDATORS` provider, a provider with an extensible collection of validators.
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive-providers" title="shared/forbidden-name.directive.ts (providers)" linenums="false"> <code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive-providers" header="shared/forbidden-name.directive.ts (providers)" linenums="false">
</code-example> </code-example>
The directive class then implements the `Validator` interface, so that it can easily integrate The directive class then implements the `Validator` interface, so that it can easily integrate
with Angular forms. Here is the rest of the directive to help you get an idea of how it all with Angular forms. Here is the rest of the directive to help you get an idea of how it all
comes together: comes together:
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive" title="shared/forbidden-name.directive.ts (directive)"> <code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive" header="shared/forbidden-name.directive.ts (directive)">
</code-example> </code-example>
Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector, `appForbiddenName`, to any input element to activate it. For example: Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector, `appForbiddenName`, to any input element to activate it. For example:
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-input" title="template/hero-form-template.component.html (forbidden-name-input)" linenums="false"> <code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-input" header="template/hero-form-template.component.html (forbidden-name-input)" linenums="false">
</code-example> </code-example>
@ -204,7 +204,7 @@ Like in AngularJS, Angular automatically mirrors many control properties onto th
The hero form uses the `.ng-valid` and `.ng-invalid` classes to The hero form uses the `.ng-valid` and `.ng-invalid` classes to
set the color of each form control's border. set the color of each form control's border.
<code-example path="form-validation/src/assets/forms.css" title="forms.css (status classes)"> <code-example path="form-validation/src/assets/forms.css" header="forms.css (status classes)">
</code-example> </code-example>
@ -245,7 +245,7 @@ const heroForm = new FormGroup({
The validator code is as follows: The validator code is as follows:
<code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-validator" title="shared/identity-revealed.directive.ts" linenums="false"> <code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-validator" header="shared/identity-revealed.directive.ts" linenums="false">
</code-example> </code-example>
The identity validator implements the `ValidatorFn` interface. It takes an Angular control object as an argument and returns either null if the form is valid, or `ValidationErrors` otherwise. The identity validator implements the `ValidatorFn` interface. It takes an Angular control object as an argument and returns either null if the form is valid, or `ValidationErrors` otherwise.
@ -255,7 +255,7 @@ First we retrieve the child controls by calling the `FormGroup`'s [get](api/form
If the values do not match, the hero's identity remains secret, and we can safely return null. Otherwise, the hero's identity is revealed and we must mark the form as invalid by returning an error object. If the values do not match, the hero's identity remains secret, and we can safely return null. Otherwise, the hero's identity is revealed and we must mark the form as invalid by returning an error object.
Next, to provide better user experience, we show an appropriate error message when the form is invalid. Next, to provide better user experience, we show an appropriate error message when the form is invalid.
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="cross-validation-error-message" title="reactive/hero-form-template.component.html" linenums="false"> <code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="cross-validation-error-message" header="reactive/hero-form-template.component.html" linenums="false">
</code-example> </code-example>
Note that we check if: Note that we check if:
@ -265,15 +265,15 @@ Note that we check if:
### Adding to template driven forms ### Adding to template driven forms
First we must create a directive that will wrap the validator function. We provide it as the validator using the `NG_VALIDATORS` token. If you are not sure why, or you do not fully understand the syntax, revisit the previous [section](guide/form-validation#adding-to-template-driven-forms). First we must create a directive that will wrap the validator function. We provide it as the validator using the `NG_VALIDATORS` token. If you are not sure why, or you do not fully understand the syntax, revisit the previous [section](guide/form-validation#adding-to-template-driven-forms).
<code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-directive" title="shared/identity-revealed.directive.ts" linenums="false"> <code-example path="form-validation/src/app/shared/identity-revealed.directive.ts" region="cross-validation-directive" header="shared/identity-revealed.directive.ts" linenums="false">
</code-example> </code-example>
Next, we have to add the directive to the html template. Since the validator must be registered at the highest level in the form, we put the directive on the `form` tag. Next, we have to add the directive to the html template. Since the validator must be registered at the highest level in the form, we put the directive on the `form` tag.
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-register-validator" title="template/hero-form-template.component.html" linenums="false"> <code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-register-validator" header="template/hero-form-template.component.html" linenums="false">
</code-example> </code-example>
To provide better user experience, we show an appropriate error message when the form is invalid. To provide better user experience, we show an appropriate error message when the form is invalid.
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-error-message" title="template/hero-form-template.component.html" linenums="false"> <code-example path="form-validation/src/app/template/hero-form-template.component.html" region="cross-validation-error-message" header="template/hero-form-template.component.html" linenums="false">
</code-example> </code-example>
Note that we check if: Note that we check if:

View File

@ -1,21 +1,21 @@
# Introduction to forms in Angular # Introduction to forms in Angular
Handling user input with forms is the cornerstone of many common applications. Applications use forms to enable users log in, to update a profile, to enter sensitive information, and to perform many other data-entry tasks. Handling user input with forms is the cornerstone of many common applications. Applications use forms to enable users to log in, to update a profile, to enter sensitive information, and to perform many other data-entry tasks.
Angular provides two different approaches to handling user input through forms: reactive and template-driven. Both capture user input events from the view, validate the user input, create a form model and data model to update, and provide a way to track changes. Angular provides two different approaches to handling user input through forms: reactive and template-driven. Both capture user input events from the view, validate the user input, create a form model and data model to update, and provide a way to track changes.
Reactive and template-driven forms differ, however, in how they do the work of processing and managing forms and form data. Each offers different advantages. Reactive and template-driven forms process and manage form data differently. Each offers different advantages.
**In general:** **In general:**
* **Reactive forms** are more robust: they are more scalable, reusable, and testable. If forms are a key part of your application, or you're already using reactive patterns for building your application, use reactive forms. * **Reactive forms** are more robust: they're more scalable, reusable, and testable. If forms are a key part of your application, or you're already using reactive patterns for building your application, use reactive forms.
* **Template-driven forms** are useful for adding a simple form to an app, such as an email list signup form. They are easy to add to an app, but they do not scale as well as reactive forms. If you have very basic form requirements and logic that can be managed solely in the template, use template-driven forms. * **Template-driven forms** are useful for adding a simple form to an app, such as an email list signup form. They're easy to add to an app, but they don't scale as well as reactive forms. If you have very basic form requirements and logic that can be managed solely in the template, use template-driven forms.
This guide provides information to help you decide which approach works best for your situation. It introduces the common building blocks used by both approaches. It also summarizes the key differences between the two approaches, and demonstrates those differences in the context of setup, data flow, and testing. This guide provides information to help you decide which type of form works best for your situation. It introduces the common building blocks used by both approaches. It also summarizes the key differences between the two approaches, and demonstrates those differences in the context of setup, data flow, and testing.
<div class="alert is-important"> <div class="alert is-helpful">
*Note:* For complete information about each kind of form, see the [Reactive Forms](guide/reactive-forms) and [Template-driven Forms](guide/forms) guides. **Note:** For complete information about each kind of form, see [Reactive Forms](guide/reactive-forms) and [Template-driven Forms](guide/forms).
</div> </div>
@ -30,7 +30,7 @@ The table below summarizes the key differences between reactive and template-dri
||Reactive|Template-driven| ||Reactive|Template-driven|
|--- |--- |--- | |--- |--- |--- |
|Setup (form model)|More explicit, created in the component class.|Less explicit, created by the directives.| |Setup (form model)|More explicit, created in component class|Less explicit, created by directives|
|Data model|Structured|Unstructured| |Data model|Structured|Unstructured|
|Predictability|Synchronous|Asynchronous| |Predictability|Synchronous|Asynchronous|
|Form validation|Functions|Directives| |Form validation|Functions|Directives|
@ -41,35 +41,41 @@ The table below summarizes the key differences between reactive and template-dri
Both reactive and template-driven forms share underlying building blocks. Both reactive and template-driven forms share underlying building blocks.
- A `FormControl` instance that tracks the value and validation status of an individual form control.
- A `FormGroup` instance that tracks the same values and status for a collection of form controls.
- A `FormArray` instance that tracks the same values and status for an array of form controls.
- A `ControlValueAccessor` that creates a bridge between Angular `FormControl` instances and native DOM elements.
How these control instances are created and managed with reactive and template-driven forms is introduced in the [form model setup](#setup-the-form-model) section below and detailed further in the [data flow section](#data-flow-in-forms) of this guide. * `FormControl` tracks the value and validation status of an individual form control.
## Setup: The form model * `FormGroup` tracks the same values and status for a collection of form controls.
Reactive and template-driven forms both use a form model to track value changes between Angular forms and form input elements. The examples below show how the form model is defined and created. * `FormArray` tracks the same values and status for an array of form controls.
* `ControlValueAccessor` creates a bridge between Angular `FormControl` instances and native DOM elements.
See the [Form model setup](#setup-the-form-model) section below for an introduction to how these control instances are created and managed with reactive and template-driven forms. Further details are provided in the [data flow section](#data-flow-in-forms) of this guide.
{@a setup-the-form-model}
## Form model setup
Reactive and template-driven forms both use a form model to track value changes between Angular forms and form input elements. The examples below show how the form model is defined and created.
### Setup in reactive forms ### Setup in reactive forms
Here is a component with an input field for a single control implemented using reactive forms. Here's a component with an input field for a single control implemented using reactive forms.
<code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.ts"> <code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.ts">
</code-example> </code-example>
The source of truth provides the value and status of the form element at a given point in time. In reactive forms, the form model is source of truth. The form model in the above example is the `FormControl` instance. The source of truth provides the value and status of the form element at a given point in time. In reactive forms, the form model is the source of truth. In the example above, the form model is the `FormControl` instance.
<figure> <figure>
<img src="generated/images/guide/forms-overview/key-diff-reactive-forms.png" alt="Reactive forms key differences"> <img src="generated/images/guide/forms-overview/key-diff-reactive-forms.png" alt="Reactive forms key differences">
</figure> </figure>
With reactive forms, the form model is explicitly defined in the component class. The reactive form directive (in this case, `FormControlDirective`) then links the existing form control instance to a specific form element in the view using a value accessor (instance of `ControlValueAccessor`). With reactive forms, the form model is explicitly defined in the component class. The reactive form directive (in this case, `FormControlDirective`) then links the existing `FormControl` instance to a specific form element in the view using a value accessor (`ControlValueAccessor` instance).
### Setup in template-driven forms ### Setup in template-driven forms
Here is the same component with an input field for a single control implemented using template-driven forms. Here's the same component with an input field for a single control implemented using template-driven forms.
<code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.ts"> <code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.ts">
</code-example> </code-example>
@ -80,23 +86,25 @@ In template-driven forms, the source of truth is the template.
<img src="generated/images/guide/forms-overview/key-diff-td-forms.png" alt="Template-driven forms key differences"> <img src="generated/images/guide/forms-overview/key-diff-td-forms.png" alt="Template-driven forms key differences">
</figure> </figure>
The abstraction of the form model promotes simplicity over structure. The template-driven form directive `NgModel` is responsible for creating and managing the form control instance for a given form element. It is less explicit, but you no longer have direct control over the form model. The abstraction of the form model promotes simplicity over structure. The template-driven form directive `NgModel` is responsible for creating and managing the `FormControl` instance for a given form element. It's less explicit, but you no longer have direct control over the form model.
{@a data-flow-in-forms}
## Data flow in forms ## Data flow in forms
When building forms in Angular, it's important to understand how the the framework handles data flowing from the user or from programmatic changes. Reactive and template-driven forms follow two different strategies when handling form input. The data flow examples below begin with the favorite color input field example from above, and they show how changes to favorite color are handled in reactive forms compared to template-driven forms. When building forms in Angular, it's important to understand how the framework handles data flowing from the user or from programmatic changes. Reactive and template-driven forms follow two different strategies when handling form input. The data flow examples below begin with the favorite color input field example from above, and then show how changes to favorite color are handled in reactive forms compared to template-driven forms.
### Data flow in reactive forms ### Data flow in reactive forms
As described above, in reactive forms each form element in the view is directly linked to a form model (`FormControl` instance). Updates from the view to model and model to view are synchronous and not dependent on the UI rendered. The diagrams below use the same favorite color example to demonstrate how data flows when an input field's value is changed from the view and then from the model. As described above, in reactive forms each form element in the view is directly linked to a form model (`FormControl` instance). Updates from the view to the model and from the model to the view are synchronous and aren't dependent on the UI rendered. The diagrams below use the same favorite color example to demonstrate how data flows when an input field's value is changed from the view and then from the model.
<figure> <figure>
<img src="generated/images/guide/forms-overview/dataflow-reactive-forms-vtm.png" alt="Reactive forms data flow - view to model" width="100%"> <img src="generated/images/guide/forms-overview/dataflow-reactive-forms-vtm.png" alt="Reactive forms data flow - view to model" width="100%">
</figure> </figure>
The steps below outline the view to model data flow. The steps below outline the data flow from view to model.
1. The end user types a value into the input element, in this case the favorite color "Blue". 1. The user types a value into the input element, in this case the favorite color *Blue*.
1. The form input element emits an "input" event with the latest value. 1. The form input element emits an "input" event with the latest value.
1. The control value accessor listening for events on the form input element immediately relays the new value to the `FormControl` instance. 1. The control value accessor listening for events on the form input element immediately relays the new value to the `FormControl` instance.
1. The `FormControl` instance emits the new value through the `valueChanges` observable. 1. The `FormControl` instance emits the new value through the `valueChanges` observable.
@ -106,37 +114,37 @@ The steps below outline the view to model data flow.
<img src="generated/images/guide/forms-overview/dataflow-reactive-forms-mtv.png" alt="Reactive forms data flow - model to view" width="100%"> <img src="generated/images/guide/forms-overview/dataflow-reactive-forms-mtv.png" alt="Reactive forms data flow - model to view" width="100%">
</figure> </figure>
The steps below outline the model to view data flow. The steps below outline the data flow from model to view.
1. The `favoriteColorControl.setValue()` method is called, which updates the `FormControl` value. 1. The user calls the `favoriteColorControl.setValue()` method, which updates the `FormControl` value.
1. The `FormControl` instance emits the new value through the `valueChanges` observable. 1. The `FormControl` instance emits the new value through the `valueChanges` observable.
1. Any subscribers to the `valueChanges` observable receive the new value. 1. Any subscribers to the `valueChanges` observable receive the new value.
1. The control value accessor on the form input element updates the element with the new value. 1. The control value accessor on the form input element updates the element with the new value.
### Data flow in template-driven forms ### Data flow in template-driven forms
In template-driven forms, each form element is linked to a directive that manages the form model internally. The diagrams below uses the same favorite color example to demonstrate how data flows when an input field's value is changed from the view and then from the model. In template-driven forms, each form element is linked to a directive that manages the form model internally. The diagrams below use the same favorite color example to demonstrate how data flows when an input field's value is changed from the view and then from the model.
<figure> <figure>
<img src="generated/images/guide/forms-overview/dataflow-td-forms-vtm.png" alt="Template-driven forms view to model data flow" width="100%"> <img src="generated/images/guide/forms-overview/dataflow-td-forms-vtm.png" alt="Template-driven forms data flow - view to model" width="100%">
</figure> </figure>
The steps below outline the view to model data flow. The steps below outline the data flow from view to model when the input value changes from *Red* to *Blue*.
1. The end user types "Blue" into the input element. 1. The user types *Blue* into the input element.
1. The input element emits an "input" event with the value "Blue". 1. The input element emits an "input" event with the value *Blue*.
1. The control value accessor attached to the input triggers the `setValue()` method on the `FormControl` instance. 1. The control value accessor attached to the input triggers the `setValue()` method on the `FormControl` instance.
1. The `FormControl` instance emits the new value through the `valueChanges` observable. 1. The `FormControl` instance emits the new value through the `valueChanges` observable.
1. Any subscribers to the `valueChanges` observable receive the new value. 1. Any subscribers to the `valueChanges` observable receive the new value.
1. The control value accessor also calls the `NgModel.viewToModel()` method which emits an `ngModelChange` event. 1. The control value accessor also calls the `NgModel.viewToModelUpdate()` method which emits an `ngModelChange` event.
1. Because the component template uses two-way data binding for the `favoriteColor`, the `favoriteColor` property in the component 1. Because the component template uses two-way data binding for the `favoriteColor` property, the `favoriteColor` property in the component
is updated to the value emitted by the `ngModelChange` event ("Blue"). is updated to the value emitted by the `ngModelChange` event (*Blue*).
<figure> <figure>
<img src="generated/images/guide/forms-overview/dataflow-td-forms-mtv.png" alt="Template-driven forms model to view data flow" width="100%"> <img src="generated/images/guide/forms-overview/dataflow-td-forms-mtv.png" alt="Template-driven forms data flow - model to view" width="100%">
</figure> </figure>
The steps below outline the model to view data flow. The steps below outline the data flow from model to view when the `favoriteColor` changes from *Blue* to *Red*.
1. The `favoriteColor` value is updated in the component. 1. The `favoriteColor` value is updated in the component.
1. Change detection begins. 1. Change detection begins.
@ -150,110 +158,117 @@ The steps below outline the model to view data flow.
## Form validation ## Form validation
Validation is an integral part of managing any set of forms. Whether youre checking for required fields or querying an external API for an existing username, Angular provides a set of built-in validators as well as the ability to create custom validators. Validation is an integral part of managing any set of forms. Whether you're checking for required fields or querying an external API for an existing username, Angular provides a set of built-in validators as well as the ability to create custom validators.
* **Reactive forms** define custom validators as **functions** that receive a control to validate. * **Reactive forms** define custom validators as **functions** that receive a control to validate.
* **Template-driven forms** are tied to template **directives**, and must provide custom validator directives that wrap validation functions. * **Template-driven forms** are tied to template **directives**, and must provide custom validator directives that wrap validation functions.
For more on form validation, see the [Form Validation](guide/form-validation) guide. For more information, see [Form Validation](guide/form-validation).
## Testing ## Testing
Testing also plays a large part in complex applications and an easier testing strategy is always welcomed. One difference in testing reactive forms and template-driven forms is their reliance on rendering the UI in order to perform assertions based on form control and form field changes. The following examples demonstrate the process of testing forms with reactive and template-driven forms. Testing plays a large part in complex applications and a simpler testing strategy is useful when validating that your forms function correctly. Reactive forms and template-driven forms have different levels of reliance on rendering the UI to perform assertions based on form control and form field changes. The following examples demonstrate the process of testing forms with reactive and template-driven forms.
### Testing reactive forms ### Testing reactive forms
Reactive forms provide a relatively easy testing strategy because they provide synchronous access to the form and data models, and they can be tested without rendering the UI. In these set of tests, controls and data are queried and manipulated through the control without interacting with the change detection cycle. Reactive forms provide a relatively easy testing strategy because they provide synchronous access to the form and data models, and they can be tested without rendering the UI. In these tests, status and data are queried and manipulated through the control without interacting with the change detection cycle.
The following tests use the favorite color components mentioned earlier to verify the view to model and model to view data flows for a reactive form. The following tests use the favorite color components mentioned earlier to verify the data flows from view to model and model to view for a reactive form.
The following test verifies the view to model data flow: The following test verifies the data flow from view to model.
<code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.spec.ts" region="view-to-model" title="Favorite color test - view to model"> <code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.spec.ts" region="view-to-model" header="Favorite color test - view to model">
</code-example> </code-example>
The steps performed in the view to model test. Here are the steps performed in the view to model test.
1. Query the view for the form input element, and create a custom "input" event for the test. 1. Query the view for the form input element, and create a custom "input" event for the test.
1. Set the new value for the input is set to *Red*, and dispatch the "input" event on the form input element. 1. Set the new value for the input to *Red*, and dispatch the "input" event on the form input element.
1. Assert that the `favoriteColor` `FormControl` instance value matches the value from the input. 1. Assert that the component's `favoriteColorControl` value matches the value from the input.
The following test verifies the model to view data flow: The following test verifies the data flow from model to view.
<code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.spec.ts" region="model-to-view" title="Favorite color test - model to view"> <code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.spec.ts" region="model-to-view" header="Favorite color test - model to view">
</code-example> </code-example>
The steps performed in the model to view test. Here are the steps performed in the model to view test.
1. Use the `favoriteColor` `FormControl` instance to set the new value. 1. Use the `favoriteColorControl`, a `FormControl` instance, to set the new value.
1. Query the view for the form input element. 1. Query the view for the form input element.
1. Assert that the new value set on the control matches the value in the input. 1. Assert that the new value set on the control matches the value in the input.
### Testing template-driven forms ### Testing template-driven forms
Writing tests with template-driven forms requires more detailed knowledge of the change detection process and how directives run on each cycle to ensure elements are queried, tested, or changed at the correct time. Writing tests with template-driven forms requires a detailed knowledge of the change detection process and an understanding of how directives run on each cycle to ensure that elements are queried, tested, or changed at the correct time.
The following tests use the favorite color components mentioned earlier to verify the view to model and model to view data flows for a template-driven form. The following tests use the favorite color components mentioned earlier to verify the data flows from view to model and model to view for a template-driven form.
The following test verifies the view to model data flow: The following test verifies the data flow from view to model.
<code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.spec.ts" region="view-to-model" title="Favorite color test - view to model"> <code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.spec.ts" region="view-to-model" header="Favorite color test - view to model">
</code-example> </code-example>
The steps performed in the view to model test. Here are the steps performed in the view to model test.
1. Query the view for the form input element, and create a custom "input" event for the test. 1. Query the view for the form input element, and create a custom "input" event for the test.
1. Set the new value for the input is set to *Red*, and dispatch the "input" event on the form input element. 1. Set the new value for the input to *Red*, and dispatch the "input" event on the form input element.
1. Run change detection through the test fixture. 1. Run change detection through the test fixture.
1. Assert that the component `favoriteColor` property value matches the value from the input. 1. Assert that the component `favoriteColor` property value matches the value from the input.
The following test verifies the model to view data flow: The following test verifies the data flow from model to view.
<code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.spec.ts" region="model-to-view" title="Favorite color test - model to view"> <code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.spec.ts" region="model-to-view" header="Favorite color test - model to view">
</code-example> </code-example>
The steps performed in the model to view test. Here are the steps performed in the model to view test.
1. Use the component instance to set the value of `favoriteColor` property. 1. Use the component instance to set the value of the `favoriteColor` property.
1. Run change detection through the test fixture. 1. Run change detection through the test fixture.
1. Use the `tick()` method to simulate passage of time within the `fakeAsync()` task. 1. Use the `tick()` method to simulate the passage of time within the `fakeAsync()` task.
1. Query the view for the form input element. 1. Query the view for the form input element.
1. Assert that the input value matches the `favoriteColor` value property in the component instance. 1. Assert that the input value matches the value of the `favoriteColor` property in the component instance.
## Mutability ## Mutability
How changes are tracked plays a role in the efficiency of your application. The change tracking method plays a role in the efficiency of your application.
- **Reactive forms** keep the data model pure by providing it as an immutable data structure. Each time a change is triggered on the data model, the `FormControl` instance returns a new data model rather than updating the data model directly. This gives you the ability track unique changes to the data model through the control's observable. This allows change detection to be more efficient because it only needs to update on unique changes. It also follows reactive patterns that integrate with observable operators to transform data.
- **Template-driven** forms rely on mutability with two-way data binding to update the data model in the component as changes are made in the template. Because there are no unique changes to track on the data model when using two-way data binding, change detection is less efficient at determining when updates are required. * **Reactive forms** keep the data model pure by providing it as an immutable data structure. Each time a change is triggered on the data model, the `FormControl` instance returns a new data model rather than updating the existing data model. This gives you the ability to track unique changes to the data model through the control's observable. This provides one way for change detection to be more efficient because it only needs to update on unique changes. It also follows reactive patterns that integrate with observable operators to transform data.
* **Template-driven** forms rely on mutability with two-way data binding to update the data model in the component as changes are made in the template. Because there are no unique changes to track on the data model when using two-way data binding, change detection is less efficient at determining when updates are required.
The difference is demonstrated in the examples above using the **favorite color** input element. The difference is demonstrated in the examples above using the **favorite color** input element.
- With reactive forms, the **`FormControl` instance** always returns a new value when the control's value is updated.
- With template-driven forms, the **favorite color property** is always modified to its new value. * With reactive forms, the **`FormControl` instance** always returns a new value when the control's value is updated.
* With template-driven forms, the **favorite color property** is always modified to its new value.
## Scalability ## Scalability
If forms are a central part of your application, scalability is very important. Being able to reuse form models across components is critical. If forms are a central part of your application, scalability is very important. Being able to reuse form models across components is critical.
- **Reactive forms** make creating large scale forms easier by providing access to low-level APIs and synchronous access to the form model.
- **Template-driven** forms focus on simple scenarios, are not as reusable, abstract away the low-level APIs and access to the form model is provided asynchronously. The abstraction with template-driven forms surfaces in testing also, where testing reactive forms requires less setup and no dependence on the change detection cycle when updating and validating the form and data models during testing.
## Final Thoughts * **Reactive forms** provide access to low-level APIs and synchronous access to the form model, making creating large-scale forms easier.
Choosing a strategy begins with understanding the strengths and weaknesses of the options presented. Low-level API and form model access, predictability, mutability, straightforward validation and testing strategies, and scalability are all important consideration in choosing the infrastructure you use when building your forms in Angular. Template-driven forms are similar to patterns in AngularJS, but they have limitations given the criteria of many modern, large-scale Angular apps. Reactive forms integrate with reactive patterns already present in other areas of the Angular architecture, and complement those requirements well. Those limitations are alleviated with reactive forms. * **Template-driven** forms focus on simple scenarios, are not as reusable, abstract away the low-level APIs, and provide asynchronous access to the form model. The abstraction with template-driven forms also surfaces in testing, where testing reactive forms requires less setup and no dependence on the change detection cycle when updating and validating the form and data models during testing.
## Final thoughts
Choosing a strategy begins with understanding the strengths and weaknesses of the options presented. Low-level API and form model access, predictability, mutability, straightforward validation and testing strategies, and scalability are all important considerations in choosing the infrastructure you use to build your forms in Angular. Template-driven forms are similar to patterns in AngularJS, but they have limitations given the criteria of many modern, large-scale Angular apps. Reactive forms minimize these limitations. Reactive forms integrate with reactive patterns already present in other areas of the Angular architecture, and complement those requirements well.
## Next steps
## Next Steps
The following guides are the next steps in the learning process.
To learn more about reactive forms, see the following guides: To learn more about reactive forms, see the following guides:
* [Reactive Forms](guide/reactive-forms) * [Reactive Forms](guide/reactive-forms)
* [Form Validation](guide/form-validation#reactive-form-validation) * [Form Validation](guide/form-validation#reactive-form-validation)
* [Dynamic forms](guide/dynamic-form) * [Dynamic Forms](guide/dynamic-form)
To learn more about tempate-driven forms, see the following guides: To learn more about template-driven forms, see the following guides:
* [Template-driven Forms](guide/forms) * [Template-driven Forms](guide/forms#template-driven-forms)
* [Form Validation](guide/form-validation#template-driven-validation) * [Form Validation](guide/form-validation#template-driven-validation)

View File

@ -1,4 +1,4 @@
# Forms # Template-driven forms
Forms are the mainstay of business applications. Forms are the mainstay of business applications.
You use forms to log in, submit a help request, place an order, book a flight, You use forms to log in, submit a help request, place an order, book a flight,
@ -7,6 +7,8 @@ schedule a meeting, and perform countless other data-entry tasks.
In developing a form, it's important to create a data-entry experience that guides the In developing a form, it's important to create a data-entry experience that guides the
user efficiently and effectively through the workflow. user efficiently and effectively through the workflow.
## Introduction to Template-driven forms
Developing forms requires design skills (which are out of scope for this page), as well as framework support for Developing forms requires design skills (which are out of scope for this page), as well as framework support for
*two-way data binding, change tracking, validation, and error handling*, *two-way data binding, change tracking, validation, and error handling*,
which you'll learn about on this page. which you'll learn about on this page.
@ -24,8 +26,6 @@ You can run the <live-example></live-example> in Stackblitz and download the cod
{@a template-driven} {@a template-driven}
## Template-driven forms
You can build forms by writing templates in the Angular [template syntax](guide/template-syntax) with You can build forms by writing templates in the Angular [template syntax](guide/template-syntax) with
the form-specific directives and techniques described in this page. the form-specific directives and techniques described in this page.
@ -99,7 +99,7 @@ A model can be as simple as a "property bag" that holds facts about a thing of a
That describes well the `Hero` class with its three required fields (`id`, `name`, `power`) That describes well the `Hero` class with its three required fields (`id`, `name`, `power`)
and one optional field (`alterEgo`). and one optional field (`alterEgo`).
Using the Angular CLI, generate a new class named `Hero`: Using the Angular CLI command [`ng generate class`](cli/generate), generate a new class named `Hero`:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
@ -109,7 +109,7 @@ Using the Angular CLI, generate a new class named `Hero`:
With this content: With this content:
<code-example path="forms/src/app/hero.ts" title="src/app/hero.ts"> <code-example path="forms/src/app/hero.ts" header="src/app/hero.ts">
</code-example> </code-example>
@ -132,7 +132,7 @@ An Angular form has two parts: an HTML-based _template_ and a component _class_
to handle data and user interactions programmatically. to handle data and user interactions programmatically.
Begin with the class because it states, in brief, what the hero editor can do. Begin with the class because it states, in brief, what the hero editor can do.
Using the Angular CLI, generate a new component named `HeroForm`: Using the Angular CLI command [`ng generate component`](cli/generate), generate a new component named `HeroForm`:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
@ -142,7 +142,7 @@ Using the Angular CLI, generate a new component named `HeroForm`:
With this content: With this content:
<code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" title="src/app/hero-form/hero-form.component.ts (v1)" region="v1"> <code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" header="src/app/hero-form/hero-form.component.ts (v1)" region="v1">
</code-example> </code-example>
@ -176,7 +176,7 @@ Because template-driven forms are in their own module, you need to add the `Form
Update it with the following: Update it with the following:
<code-example path="forms/src/app/app.module.ts" title="src/app/app.module.ts"> <code-example path="forms/src/app/app.module.ts" header="src/app/app.module.ts">
</code-example> </code-example>
@ -204,7 +204,7 @@ Update it with the following:
Replace the contents of its template with the following: Replace the contents of its template with the following:
<code-example path="forms/src/app/app.component.html" title="src/app/app.component.html"> <code-example path="forms/src/app/app.component.html" header="src/app/app.component.html">
</code-example> </code-example>
@ -221,7 +221,7 @@ Replace the contents of its template with the following:
Update the template file with the following contents: Update the template file with the following contents:
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="start" title="src/app/hero-form/hero-form.component.html"> <code-example path="forms/src/app/hero-form/hero-form.component.html" region="start" header="src/app/hero-form/hero-form.component.html">
</code-example> </code-example>
@ -259,7 +259,7 @@ Bootstrap gives the form a little style.
To add the stylesheet, open `styles.css` and add the following import line at the top: To add the stylesheet, open `styles.css` and add the following import line at the top:
<code-example path="forms/src/styles.1.css" linenums="false" title="src/styles.css"> <code-example path="forms/src/styles.1.css" linenums="false" header="src/styles.css">
</code-example> </code-example>
@ -274,7 +274,7 @@ a technique seen previously in the [Displaying Data](guide/displaying-data) page
Add the following HTML *immediately below* the *Alter Ego* group: Add the following HTML *immediately below* the *Alter Ego* group:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (powers)" region="powers"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (powers)" region="powers">
</code-example> </code-example>
@ -307,7 +307,7 @@ makes binding the form to the model easy.
Find the `<input>` tag for *Name* and update it like this: Find the `<input>` tag for *Name* and update it like this:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-1"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-1">
</code-example> </code-example>
@ -325,7 +325,7 @@ You need one more addition to display the data. Declare
a template variable for the form. Update the `<form>` tag with a template variable for the form. Update the `<form>` tag with
`#heroForm="ngForm"` as follows: `#heroForm="ngForm"` as follows:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="template-variable"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="template-variable">
</code-example> </code-example>
@ -391,7 +391,7 @@ Then you can confirm that two-way data binding works *for the entire hero model*
After revision, the core of the form should look like this: After revision, the core of the form should look like this:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModel-2"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModel-2">
</code-example> </code-example>
@ -493,7 +493,7 @@ You can leverage those class names to change the appearance of the control.
Temporarily add a [template reference variable](guide/template-syntax#ref-vars) named `spy` Temporarily add a [template reference variable](guide/template-syntax#ref-vars) named `spy`
to the _Name_ `<input>` tag and use it to display the input's CSS classes. to the _Name_ `<input>` tag and use it to display the input's CSS classes.
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-2"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="ngModelName-2">
</code-example> </code-example>
@ -535,13 +535,13 @@ on the left of the input box:
You achieve this effect by adding these class definitions to a new `forms.css` file You achieve this effect by adding these class definitions to a new `forms.css` file
that you add to the project as a sibling to `index.html`: that you add to the project as a sibling to `index.html`:
<code-example path="forms/src/assets/forms.css" title="src/assets/forms.css"> <code-example path="forms/src/assets/forms.css" header="src/assets/forms.css">
</code-example> </code-example>
Update the `<head>` of `index.html` to include this style sheet: Update the `<head>` of `index.html` to include this style sheet:
<code-example path="forms/src/index.html" linenums="false" title="src/index.html (styles)" region="styles"> <code-example path="forms/src/index.html" linenums="false" header="src/index.html (styles)" region="styles">
</code-example> </code-example>
@ -564,7 +564,7 @@ To achieve this effect, extend the `<input>` tag with the following:
Here's an example of an error message added to the _name_ input box: Here's an example of an error message added to the _name_ input box:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="name-with-error-msg"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="name-with-error-msg">
</code-example> </code-example>
@ -583,7 +583,7 @@ Here you created a variable called `name` and gave it the value "ngModel".
You control visibility of the name error message by binding properties of the `name` You control visibility of the name error message by binding properties of the `name`
control to the message `<div>` element's `hidden` property. control to the message `<div>` element's `hidden` property.
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (hidden-error-msg)" region="hidden-error-msg"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (hidden-error-msg)" region="hidden-error-msg">
</code-example> </code-example>
@ -609,11 +609,11 @@ power to valid values.
Now you'll add a new hero in this form. Now you'll add a new hero in this form.
Place a *New Hero* button at the bottom of the form and bind its click event to a `newHero` component method. Place a *New Hero* button at the bottom of the form and bind its click event to a `newHero` component method.
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-no-reset" title="src/app/hero-form/hero-form.component.html (New Hero button)"> <code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-no-reset" header="src/app/hero-form/hero-form.component.html (New Hero button)">
</code-example> </code-example>
<code-example path="forms/src/app/hero-form/hero-form.component.ts" region="new-hero" title="src/app/hero-form/hero-form.component.ts (New Hero method)" linenums="false"> <code-example path="forms/src/app/hero-form/hero-form.component.ts" region="new-hero" header="src/app/hero-form/hero-form.component.ts (New Hero method)" linenums="false">
</code-example> </code-example>
@ -634,7 +634,7 @@ Replacing the hero object *did not restore the pristine state* of the form contr
You have to clear all of the flags imperatively, which you can do You have to clear all of the flags imperatively, which you can do
by calling the form's `reset()` method after calling the `newHero()` method. by calling the form's `reset()` method after calling the `newHero()` method.
<code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-form-reset" title="src/app/hero-form/hero-form.component.html (Reset the form)"> <code-example path="forms/src/app/hero-form/hero-form.component.html" region="new-hero-button-form-reset" header="src/app/hero-form/hero-form.component.html (Reset the form)">
</code-example> </code-example>
@ -651,7 +651,7 @@ A "form submit" is useless at the moment.
To make it useful, bind the form's `ngSubmit` event property To make it useful, bind the form's `ngSubmit` event property
to the hero form component's `onSubmit()` method: to the hero form component's `onSubmit()` method:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (ngSubmit)" region="ngSubmit"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (ngSubmit)" region="ngSubmit">
</code-example> </code-example>
@ -664,7 +664,7 @@ You'll bind the form's overall validity via
the `heroForm` variable to the button's `disabled` property the `heroForm` variable to the button's `disabled` property
using an event binding. Here's the code: using an event binding. Here's the code:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (submit-button)" region="submit-button"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (submit-button)" region="submit-button">
</code-example> </code-example>
@ -703,7 +703,7 @@ hide the data entry area and display something else.
Wrap the form in a `<div>` and bind Wrap the form in a `<div>` and bind
its `hidden` property to the `HeroFormComponent.submitted` property. its `hidden` property to the `HeroFormComponent.submitted` property.
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="edit-div"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="edit-div">
</code-example> </code-example>
@ -711,7 +711,7 @@ The main form is visible from the start because the
`submitted` property is false until you submit the form, `submitted` property is false until you submit the form,
as this fragment from the `HeroFormComponent` shows: as this fragment from the `HeroFormComponent` shows:
<code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" title="src/app/hero-form/hero-form.component.ts (submitted)" region="submitted"> <code-example path="forms/src/app/hero-form/hero-form.component.ts" linenums="false" header="src/app/hero-form/hero-form.component.ts (submitted)" region="submitted">
</code-example> </code-example>
@ -721,7 +721,7 @@ as planned.
Now the app needs to show something else while the form is in the submitted state. Now the app needs to show something else while the form is in the submitted state.
Add the following HTML below the `<div>` wrapper you just wrote: Add the following HTML below the `<div>` wrapper you just wrote:
<code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" title="src/app/hero-form/hero-form.component.html (excerpt)" region="submitted"> <code-example path="forms/src/app/hero-form/hero-form.component.html" linenums="false" header="src/app/hero-form/hero-form.component.html (excerpt)" region="submitted">
</code-example> </code-example>
@ -752,35 +752,35 @@ Heres the code for the final version of the application:
<code-tabs> <code-tabs>
<code-pane title="hero-form/hero-form.component.ts" path="forms/src/app/hero-form/hero-form.component.ts" region="final"> <code-pane header="hero-form/hero-form.component.ts" path="forms/src/app/hero-form/hero-form.component.ts" region="final">
</code-pane> </code-pane>
<code-pane title="hero-form/hero-form.component.html" path="forms/src/app/hero-form/hero-form.component.html" region="final"> <code-pane header="hero-form/hero-form.component.html" path="forms/src/app/hero-form/hero-form.component.html" region="final">
</code-pane> </code-pane>
<code-pane title="hero.ts" path="forms/src/app/hero.ts"> <code-pane header="hero.ts" path="forms/src/app/hero.ts">
</code-pane> </code-pane>
<code-pane title="app.module.ts" path="forms/src/app/app.module.ts"> <code-pane header="app.module.ts" path="forms/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="app.component.html" path="forms/src/app/app.component.html"> <code-pane header="app.component.html" path="forms/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane title="app.component.ts" path="forms/src/app/app.component.ts"> <code-pane header="app.component.ts" path="forms/src/app/app.component.ts">
</code-pane> </code-pane>
<code-pane title="main.ts" path="forms/src/main.ts"> <code-pane header="main.ts" path="forms/src/main.ts">
</code-pane> </code-pane>
<code-pane title="forms.css" path="forms/src/assets/forms.css"> <code-pane header="forms.css" path="forms/src/assets/forms.css">
</code-pane> </code-pane>

View File

@ -71,7 +71,7 @@ of some of the things they contain:
When you use these Angular modules, import them in `AppModule`, When you use these Angular modules, import them in `AppModule`,
or your feature module as appropriate, and list them in the `@NgModule` or your feature module as appropriate, and list them in the `@NgModule`
`imports` array. For example, in the basic app generated by the CLI, `imports` array. For example, in the basic app generated by the [Angular CLI](cli),
`BrowserModule` is the first import at the top of the `AppModule`, `BrowserModule` is the first import at the top of the `AppModule`,
`app.module.ts`. `app.module.ts`.

View File

@ -77,7 +77,7 @@ A way to initialize and launch an app or system.
In Angular, an app's root NgModule (`AppModule`) has a `bootstrap` property that identifies the app's top-level [components](guide/glossary#component). In Angular, an app's root NgModule (`AppModule`) has a `bootstrap` property that identifies the app's top-level [components](guide/glossary#component).
During the bootstrap process, Angular creates and inserts these components into the `index.html` host web page. During the bootstrap process, Angular creates and inserts these components into the `index.html` host web page.
You can bootstrap multiple apps in the same `index.html`. Each app ccontains its own components. You can bootstrap multiple apps in the same `index.html`. Each app contains its own components.
Learn more in [Bootstrapping](guide/bootstrapping). Learn more in [Bootstrapping](guide/bootstrapping).
@ -130,10 +130,10 @@ A [decorator](guide/glossary#decorator) statement immediately before a field in
## command-line interface (CLI) ## command-line interface (CLI)
The [Angular CLI](https://cli.angular.io/) is a command-line tool for managing the Angular development cycle. Use it to create the initial filesystem scaffolding for a [workspace](guide/glossary#workspace) or [project](guide/glossary#project), and to run [schematics](guide/glossary#schematic) that add and modify code for initial generic versions of various elements. The CLI supports all stages of the development cycle, including building, testing, bundling, and deployment. The [Angular CLI](cli) is a command-line tool for managing the Angular development cycle. Use it to create the initial filesystem scaffolding for a [workspace](guide/glossary#workspace) or [project](guide/glossary#project), and to run [schematics](guide/glossary#schematic) that add and modify code for initial generic versions of various elements. The CLI supports all stages of the development cycle, including building, testing, bundling, and deployment.
* To begin using the CLI for a new project, see [QuickStart](guide/quickstart). * To begin using the CLI for a new project, see [Getting Started](guide/quickstart).
* To learn more about the full capabilities of the CLI, see the [Angular CLI documentation](https://github.com/angular/angular-cli/wiki). * To learn more about the full capabilities of the CLI, see the [CLI command reference](cli).
{@a component} {@a component}
@ -621,8 +621,7 @@ For more information, see [Routing and Navigation](guide/router).
A scaffolding library that defines how to generate or transform a programming project by creating, modifying, refactoring, or moving files and code. A scaffolding library that defines how to generate or transform a programming project by creating, modifying, refactoring, or moving files and code.
The Angular [CLI](guide/glossary#cli) uses schematics to generate and modify [Angular projects](guide/glossary#project) and parts of projects. The Angular [CLI](guide/glossary#cli) uses schematics to generate and modify [Angular projects](guide/glossary#project) and parts of projects.
* Angular provides a set of schematics for use with the CLI. * Angular provides a set of schematics for use with the CLI. See the [Angular CLI command reference](cli). The [`ng add`](cli/add) command runs schematics as part of adding a library to your project. The [`ng generate`](cli/generate) command runs schematics to create apps, libraries, and Angular code constructs.
For details, see [Angular CLI documentation](https://github.com/angular/angular-cli/wiki).
* Library developers can create schematics that enable the CLI to generate their published libraries. * Library developers can create schematics that enable the CLI to generate their published libraries.
For more information, see [devkit documentation](https://www.npmjs.com/package/@angular-devkit/schematics). For more information, see [devkit documentation](https://www.npmjs.com/package/@angular-devkit/schematics).
@ -636,7 +635,7 @@ NgModules are delivered within scoped packages whose names begin with the Angula
Import a scoped package in the same way that you import a normal package. Import a scoped package in the same way that you import a normal package.
<code-example path="architecture/src/app/app.component.ts" linenums="false" title="architecture/src/app/app.component.ts (import)" region="import"> <code-example path="architecture/src/app/app.component.ts" linenums="false" header="architecture/src/app/app.component.ts (import)" region="import">
</code-example> </code-example>
@ -785,7 +784,7 @@ See [custom element](guide/glossary#custom-element).
## workspace ## workspace
In Angular, a folder that contains [projects](guide/glossary#project) (that is, apps and libraries). In Angular, a folder that contains [projects](guide/glossary#project) (that is, apps and libraries).
The [CLI](guide/glossary#cli) `new` command creates a workspace to contain projects. The [CLI](guide/glossary#cli) `ng new` command creates a workspace to contain projects.
Commands that create or operate on apps and libraries (such as `add` and `generate`) must be executed from within a workspace folder. Commands that create or operate on apps and libraries (such as `add` and `generate`) must be executed from within a workspace folder.
{@a X} {@a X}

View File

@ -23,9 +23,9 @@ When you specify providers in the `@Injectable()` decorator of the service itsel
* Learn more about [tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers). * Learn more about [tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers).
You're likely to inject `UserService` in many places throughout the app and will want to inject the same service instance every time. Providing `UserService` through the `root` injector is a good choice, and is the default that the CLI uses when you generate a service for your app. You're likely to inject `UserService` in many places throughout the app and will want to inject the same service instance every time. Providing `UserService` through the `root` injector is a good choice, and is the default that the [Angular CLI](cli) uses when you generate a service for your app.
<div class="alert-is-helpful"> <div class="alert is-helpful">
<header>Platform injector</header> <header>Platform injector</header>
When you use `providedIn:'root'`, you are configuring the root injector for the _app_, which is the injector for `AppModule`. When you use `providedIn:'root'`, you are configuring the root injector for the _app_, which is the injector for `AppModule`.
@ -75,7 +75,7 @@ When an injectable class provides its own service to the `root` injector, the se
The following example configures a provider for `HeroService` using the `@Injectable()` decorator on the class. The following example configures a provider for `HeroService` using the `@Injectable()` decorator on the class.
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" title="src/app/heroes/heroes.service.ts" linenums="false"> </code-example> <code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" header="src/app/heroes/heroes.service.ts" linenums="false"> </code-example>
This configuration tells Angular that the app's root injector is responsible for creating an This configuration tells Angular that the app's root injector is responsible for creating an
instance of `HeroService` by invoking its constructor, instance of `HeroService` by invoking its constructor,
@ -92,7 +92,7 @@ Instead of specifying the `root` injector, you can set `providedIn` to a specifi
For example, in the following excerpt, the `@Injectable()` decorator configures a provider For example, in the following excerpt, the `@Injectable()` decorator configures a provider
that is available in any injector that includes the `HeroModule`. that is available in any injector that includes the `HeroModule`.
<code-example path="dependency-injection/src/app/heroes/hero.service.4.ts" title="src/app/heroes/hero.service.ts" linenums="false"> </code-example> <code-example path="dependency-injection/src/app/heroes/hero.service.4.ts" header="src/app/heroes/hero.service.ts" linenums="false"> </code-example>
This is generally no different from configuring the injector of the NgModule itself, This is generally no different from configuring the injector of the NgModule itself,
except that the service is tree-shakable if the NgModule doesn't use it. except that the service is tree-shakable if the NgModule doesn't use it.
@ -117,7 +117,7 @@ Here is an example of the case where the component router configuration includes
a non-default [location strategy](guide/router#location-strategy) by listing its provider a non-default [location strategy](guide/router#location-strategy) by listing its provider
in the `providers` list of the `AppModule`. in the `providers` list of the `AppModule`.
<code-example path="dependency-injection-in-action/src/app/app.module.ts" region="providers" title="src/app/app.module.ts (providers)" linenums="false"> <code-example path="dependency-injection-in-action/src/app/app.module.ts" region="providers" header="src/app/app.module.ts (providers)" linenums="false">
</code-example> </code-example>
@ -132,7 +132,7 @@ by configuring the provider at the component level using the `@Component` metada
The following example is a revised `HeroesComponent` that specifies `HeroService` in its `providers` array. `HeroService` can provide heroes to instances of this component, or to any child component instances. The following example is a revised `HeroesComponent` that specifies `HeroService` in its `providers` array. `HeroService` can provide heroes to instances of this component, or to any child component instances.
<code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" title="src/app/heroes/heroes.component.ts" linenums="false"> <code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts" linenums="false">
</code-example> </code-example>
### Element injectors ### Element injectors
@ -207,7 +207,7 @@ that would make the `VillainsService` available everywhere in the application, i
Instead, you can provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this: Instead, you can provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this:
<code-example path="hierarchical-dependency-injection/src/app/villains-list.component.ts" linenums="false" title="src/app/villains-list.component.ts (metadata)" region="metadata"> <code-example path="hierarchical-dependency-injection/src/app/villains-list.component.ts" linenums="false" header="src/app/villains-list.component.ts (metadata)" region="metadata">
</code-example> </code-example>
@ -250,14 +250,14 @@ It caches a single `HeroTaxReturn`, tracks changes to that return, and can save
It also delegates to the application-wide singleton `HeroService`, which it gets by injection. It also delegates to the application-wide singleton `HeroService`, which it gets by injection.
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.service.ts" title="src/app/hero-tax-return.service.ts"> <code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.service.ts" header="src/app/hero-tax-return.service.ts">
</code-example> </code-example>
Here is the `HeroTaxReturnComponent` that makes use of it. Here is the `HeroTaxReturnComponent` that makes use of it.
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" title="src/app/hero-tax-return.component.ts"> <code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" header="src/app/hero-tax-return.component.ts">
</code-example> </code-example>
@ -273,7 +273,7 @@ Every component would share the same service instance, and each component would
To prevent this, we configure the component-level injector of `HeroTaxReturnComponent` to provide the service, using the `providers` property in the component metadata. To prevent this, we configure the component-level injector of `HeroTaxReturnComponent` to provide the service, using the `providers` property in the component metadata.
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" linenums="false" title="src/app/hero-tax-return.component.ts (providers)" region="providers"> <code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" linenums="false" header="src/app/hero-tax-return.component.ts (providers)" region="providers">
</code-example> </code-example>

View File

@ -28,7 +28,7 @@ Most apps do so in the root `AppModule`.
<code-example <code-example
path="http/src/app/app.module.ts" path="http/src/app/app.module.ts"
region="sketch" region="sketch"
title="app/app.module.ts (excerpt)" linenums="false"> header="app/app.module.ts (excerpt)" linenums="false">
</code-example> </code-example>
Having imported `HttpClientModule` into the `AppModule`, you can inject the `HttpClient` Having imported `HttpClientModule` into the `AppModule`, you can inject the `HttpClient`
@ -37,7 +37,7 @@ into an application class as shown in the following `ConfigService` example.
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="proto" region="proto"
title="app/config/config.service.ts (excerpt)" linenums="false"> header="app/config/config.service.ts (excerpt)" linenums="false">
</code-example> </code-example>
## Getting JSON data ## Getting JSON data
@ -48,7 +48,7 @@ that specifies resource URLs.
<code-example <code-example
path="http/src/assets/config.json" path="http/src/assets/config.json"
title="assets/config.json" linenums="false"> header="assets/config.json" linenums="false">
</code-example> </code-example>
The `ConfigService` fetches this file with a `get()` method on `HttpClient`. The `ConfigService` fetches this file with a `get()` method on `HttpClient`.
@ -56,7 +56,7 @@ The `ConfigService` fetches this file with a `get()` method on `HttpClient`.
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfig_1" region="getConfig_1"
title="app/config/config.service.ts (getConfig v.1)" linenums="false"> header="app/config/config.service.ts (getConfig v.1)" linenums="false">
</code-example> </code-example>
A component, such as `ConfigComponent`, injects the `ConfigService` and calls A component, such as `ConfigComponent`, injects the `ConfigService` and calls
@ -65,7 +65,7 @@ the `getConfig` service method.
<code-example <code-example
path="http/src/app/config/config.component.ts" path="http/src/app/config/config.component.ts"
region="v1" region="v1"
title="app/config/config.component.ts (showConfig v.1)" linenums="false"> header="app/config/config.component.ts (showConfig v.1)" linenums="false">
</code-example> </code-example>
Because the service method returns an `Observable` of configuration data, Because the service method returns an `Observable` of configuration data,
@ -116,7 +116,7 @@ Then, specify that interface as the `HttpClient.get()` call's type parameter in
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfig_2" region="getConfig_2"
title="app/config/config.service.ts (getConfig v.2)" linenums="false"> header="app/config/config.service.ts (getConfig v.2)" linenums="false">
</code-example> </code-example>
The callback in the updated component method receives a typed data object, which is The callback in the updated component method receives a typed data object, which is
@ -125,7 +125,7 @@ easier and safer to consume:
<code-example <code-example
path="http/src/app/config/config.component.ts" path="http/src/app/config/config.component.ts"
region="v2" region="v2"
title="app/config/config.component.ts (showConfig v.2)" linenums="false"> header="app/config/config.component.ts (showConfig v.2)" linenums="false">
</code-example> </code-example>
### Reading the full response ### Reading the full response
@ -146,7 +146,7 @@ The component's `showConfigResponse()` method displays the response headers as w
<code-example <code-example
path="http/src/app/config/config.component.ts" path="http/src/app/config/config.component.ts"
region="showConfigResponse" region="showConfigResponse"
title="app/config/config.component.ts (showConfigResponse)" header="app/config/config.component.ts (showConfigResponse)"
linenums="false"> linenums="false">
</code-example> </code-example>
@ -161,7 +161,7 @@ You _could_ handle in the component by adding a second callback to the `.subscri
<code-example <code-example
path="http/src/app/config/config.component.ts" path="http/src/app/config/config.component.ts"
region="v3" region="v3"
title="app/config/config.component.ts (showConfig v.3 with error handling)" header="app/config/config.component.ts (showConfig v.3 with error handling)"
linenums="false"> linenums="false">
</code-example> </code-example>
@ -188,7 +188,7 @@ You might first devise an error handler like this one:
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="handleError" region="handleError"
title="app/config/config.service.ts (handleError)" linenums="false"> header="app/config/config.service.ts (handleError)" linenums="false">
</code-example> </code-example>
Notice that this handler returns an RxJS [`ErrorObservable`](#rxjs) with a user-friendly error message. Notice that this handler returns an RxJS [`ErrorObservable`](#rxjs) with a user-friendly error message.
@ -201,7 +201,7 @@ and _pipe them through_ to the error handler.
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfig_3" region="getConfig_3"
title="app/config/config.service.ts (getConfig v.3 with error handler)" linenums="false"> header="app/config/config.service.ts (getConfig v.3 with error handler)" linenums="false">
</code-example> </code-example>
### `retry()` ### `retry()`
@ -218,7 +218,7 @@ _Pipe_ it onto the `HttpClient` method result just before the error handler.
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfig" region="getConfig"
title="app/config/config.service.ts (getConfig with retry)" linenums="false"> header="app/config/config.service.ts (getConfig with retry)" linenums="false">
</code-example> </code-example>
{@a rxjs} {@a rxjs}
@ -239,7 +239,7 @@ If you're following along with these code snippets, note that you must import th
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="rxjs-imports" region="rxjs-imports"
title="app/config/config.service.ts (RxJS imports)" linenums="false"> header="app/config/config.service.ts (RxJS imports)" linenums="false">
</code-example> </code-example>
## Requesting non-JSON data ## Requesting non-JSON data
@ -252,7 +252,7 @@ as an `Observable<string>`.
<code-example <code-example
path="http/src/app/downloader/downloader.service.ts" path="http/src/app/downloader/downloader.service.ts"
region="getTextFile" region="getTextFile"
title="app/downloader/downloader.service.ts (getTextFile)" linenums="false"> header="app/downloader/downloader.service.ts (getTextFile)" linenums="false">
</code-example> </code-example>
`HttpClient.get()` returns a string rather than the default JSON because of the `responseType` option. `HttpClient.get()` returns a string rather than the default JSON because of the `responseType` option.
@ -264,7 +264,7 @@ A `download()` method in the `DownloaderComponent` initiates the request by subs
<code-example <code-example
path="http/src/app/downloader/downloader.component.ts" path="http/src/app/downloader/downloader.component.ts"
region="download" region="download"
title="app/downloader/downloader.component.ts (download)" linenums="false"> header="app/downloader/downloader.component.ts (download)" linenums="false">
</code-example> </code-example>
## Sending data to the server ## Sending data to the server
@ -289,7 +289,7 @@ to every `HttpClient` save method.
<code-example <code-example
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="http-options" region="http-options"
title="app/heroes/heroes.service.ts (httpOptions)" linenums="false"> header="app/heroes/heroes.service.ts (httpOptions)" linenums="false">
</code-example> </code-example>
### Making a POST request ### Making a POST request
@ -300,7 +300,7 @@ In the following example, the `HeroesService` posts when adding a hero to the da
<code-example <code-example
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="addHero" region="addHero"
title="app/heroes/heroes.service.ts (addHero)" linenums="false"> header="app/heroes/heroes.service.ts (addHero)" linenums="false">
</code-example> </code-example>
The `HttpClient.post()` method is similar to `get()` in that it has a type parameter The `HttpClient.post()` method is similar to `get()` in that it has a type parameter
@ -320,7 +320,7 @@ the `Observable` returned by this service method.
<code-example <code-example
path="http/src/app/heroes/heroes.component.ts" path="http/src/app/heroes/heroes.component.ts"
region="add-hero-subscribe" region="add-hero-subscribe"
title="app/heroes/heroes.component.ts (addHero)" linenums="false"> header="app/heroes/heroes.component.ts (addHero)" linenums="false">
</code-example> </code-example>
When the server responds successfully with the newly added hero, the component adds When the server responds successfully with the newly added hero, the component adds
@ -334,7 +334,7 @@ in the request URL.
<code-example <code-example
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="deleteHero" region="deleteHero"
title="app/heroes/heroes.service.ts (deleteHero)" linenums="false"> header="app/heroes/heroes.service.ts (deleteHero)" linenums="false">
</code-example> </code-example>
The `HeroesComponent` initiates the actual DELETE operation by subscribing to The `HeroesComponent` initiates the actual DELETE operation by subscribing to
@ -343,7 +343,7 @@ the `Observable` returned by this service method.
<code-example <code-example
path="http/src/app/heroes/heroes.component.ts" path="http/src/app/heroes/heroes.component.ts"
region="delete-hero-subscribe" region="delete-hero-subscribe"
title="app/heroes/heroes.component.ts (deleteHero)" linenums="false"> header="app/heroes/heroes.component.ts (deleteHero)" linenums="false">
</code-example> </code-example>
The component isn't expecting a result from the delete operation, so it subscribes without a callback. Even though you are not using the result, you still have to subscribe. Calling the `subscribe()` method _executes_ the observable, which is what initiates the DELETE request. The component isn't expecting a result from the delete operation, so it subscribes without a callback. Even though you are not using the result, you still have to subscribe. Calling the `subscribe()` method _executes_ the observable, which is what initiates the DELETE request.
@ -403,7 +403,7 @@ The following `HeroesService` example is just like the POST example.
<code-example <code-example
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="updateHero" region="updateHero"
title="app/heroes/heroes.service.ts (updateHero)" linenums="false"> header="app/heroes/heroes.service.ts (updateHero)" linenums="false">
</code-example> </code-example>
For the reasons [explained above](#always-subscribe), the caller (`HeroesComponent.update()` in this case) must `subscribe()` to the observable returned from the `HttpClient.put()` For the reasons [explained above](#always-subscribe), the caller (`HeroesComponent.update()` in this case) must `subscribe()` to the observable returned from the `HttpClient.put()`
@ -464,7 +464,7 @@ Here's a pertinent excerpt from the template:
<code-example <code-example
path="http/src/app/package-search/package-search.component.html" path="http/src/app/package-search/package-search.component.html"
region="search" region="search"
title="app/package-search/package-search.component.html (search)"> header="app/package-search/package-search.component.html (search)">
</code-example> </code-example>
The `(keyup)` event binding sends every keystroke to the component's `search()` method. The `(keyup)` event binding sends every keystroke to the component's `search()` method.
@ -476,7 +476,7 @@ That's easy to implement with RxJS operators, as shown in this excerpt.
<code-example <code-example
path="http/src/app/package-search/package-search.component.ts" path="http/src/app/package-search/package-search.component.ts"
region="debounce" region="debounce"
title="app/package-search/package-search.component.ts (excerpt))"> header="app/package-search/package-search.component.ts (excerpt))">
</code-example> </code-example>
The `searchText$` is the sequence of search-box values coming from the user. The `searchText$` is the sequence of search-box values coming from the user.
@ -543,7 +543,7 @@ To implement an interceptor, declare a class that implements the `intercept()` m
Here is a do-nothing _noop_ interceptor that simply passes the request through without touching it: Here is a do-nothing _noop_ interceptor that simply passes the request through without touching it:
<code-example <code-example
path="http/src/app/http-interceptors/noop-interceptor.ts" path="http/src/app/http-interceptors/noop-interceptor.ts"
title="app/http-interceptors/noop-interceptor.ts" header="app/http-interceptors/noop-interceptor.ts"
linenums="false"> linenums="false">
</code-example> </code-example>
@ -608,7 +608,7 @@ Consider creating a "barrel" file that gathers all the interceptor providers int
<code-example <code-example
path="http/src/app/http-interceptors/index.ts" path="http/src/app/http-interceptors/index.ts"
region="interceptor-providers" region="interceptor-providers"
title="app/http-interceptors/index.ts" linenums="false"> header="app/http-interceptors/index.ts" linenums="false">
</code-example> </code-example>
Then import and add it to the `AppModule` _providers array_ like this: Then import and add it to the `AppModule` _providers array_ like this:
@ -616,7 +616,7 @@ Then import and add it to the `AppModule` _providers array_ like this:
<code-example <code-example
path="http/src/app/app.module.ts" path="http/src/app/app.module.ts"
region="interceptor-providers" region="interceptor-providers"
title="app/app.module.ts (interceptor providers)" linenums="false"> header="app/app.module.ts (interceptor providers)" linenums="false">
</code-example> </code-example>
As you create new interceptors, add them to the `httpInterceptorProviders` array and As you create new interceptors, add them to the `httpInterceptorProviders` array and
@ -672,7 +672,7 @@ You can clone and modify the request in a single step as in this example.
<code-example <code-example
path="http/src/app/http-interceptors/ensure-https-interceptor.ts" path="http/src/app/http-interceptors/ensure-https-interceptor.ts"
region="excerpt" region="excerpt"
title="app/http-interceptors/ensure-https-interceptor.ts (excerpt)" linenums="false"> header="app/http-interceptors/ensure-https-interceptor.ts (excerpt)" linenums="false">
</code-example> </code-example>
The `clone()` method's hash argument allows you to mutate specific properties of the request while copying the others. The `clone()` method's hash argument allows you to mutate specific properties of the request while copying the others.
@ -692,7 +692,7 @@ If you must mutate the request body, copy it first, change the copy,
<code-example <code-example
path="http/src/app/http-interceptors/trim-name-interceptor.ts" path="http/src/app/http-interceptors/trim-name-interceptor.ts"
region="excerpt" region="excerpt"
title="app/http-interceptors/trim-name-interceptor.ts (excerpt)" linenums="false"> header="app/http-interceptors/trim-name-interceptor.ts (excerpt)" linenums="false">
</code-example> </code-example>
##### Clearing the request body ##### Clearing the request body
@ -718,7 +718,7 @@ adds an authorization header with that token to every outgoing request:
<code-example <code-example
path="http/src/app/http-interceptors/auth-interceptor.ts" path="http/src/app/http-interceptors/auth-interceptor.ts"
title="app/http-interceptors/auth-interceptor.ts"> header="app/http-interceptors/auth-interceptor.ts">
</code-example> </code-example>
The practice of cloning a request to set new headers is so common that The practice of cloning a request to set new headers is so common that
@ -747,7 +747,7 @@ with the injected `MessageService`.
<code-example <code-example
path="http/src/app/http-interceptors/logging-interceptor.ts" path="http/src/app/http-interceptors/logging-interceptor.ts"
region="excerpt" region="excerpt"
title="app/http-interceptors/logging-interceptor.ts)"> header="app/http-interceptors/logging-interceptor.ts)">
</code-example> </code-example>
The RxJS `tap` operator captures whether the request succeed or failed. The RxJS `tap` operator captures whether the request succeed or failed.
@ -768,7 +768,7 @@ The `CachingInterceptor` demonstrates this approach.
<code-example <code-example
path="http/src/app/http-interceptors/caching-interceptor.ts" path="http/src/app/http-interceptors/caching-interceptor.ts"
region="v1" region="v1"
title="app/http-interceptors/caching-interceptor.ts)" linenums="false"> header="app/http-interceptors/caching-interceptor.ts)" linenums="false">
</code-example> </code-example>
The `isCachable()` function determines if the request is cachable. The `isCachable()` function determines if the request is cachable.
@ -858,7 +858,7 @@ with the `reportProgress` option set true to enable tracking of progress events.
<code-example <code-example
path="http/src/app/uploader/uploader.service.ts" path="http/src/app/uploader/uploader.service.ts"
region="upload-request" region="upload-request"
title="app/uploader/uploader.service.ts (upload request)"> header="app/uploader/uploader.service.ts (upload request)">
</code-example> </code-example>
<div class="alert is-important"> <div class="alert is-important">
@ -873,7 +873,7 @@ returns an `Observable` of `HttpEvents`, the same events processed by intercepto
<code-example <code-example
path="http/src/app/uploader/uploader.service.ts" path="http/src/app/uploader/uploader.service.ts"
region="upload-body" region="upload-body"
title="app/uploader/uploader.service.ts (upload body)" linenums="false"> header="app/uploader/uploader.service.ts (upload body)" linenums="false">
</code-example> </code-example>
The `getEventMessage` method interprets each type of `HttpEvent` in the event stream. The `getEventMessage` method interprets each type of `HttpEvent` in the event stream.
@ -881,7 +881,7 @@ The `getEventMessage` method interprets each type of `HttpEvent` in the event st
<code-example <code-example
path="http/src/app/uploader/uploader.service.ts" path="http/src/app/uploader/uploader.service.ts"
region="getEventMessage" region="getEventMessage"
title="app/uploader/uploader.service.ts (getEventMessage)" linenums="false"> header="app/uploader/uploader.service.ts (getEventMessage)" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -936,7 +936,7 @@ setting up such mocking straightforward.
### Mocking philosophy ### Mocking philosophy
Angular's HTTP testing library is designed for a pattern of testing wherein Angular's HTTP testing library is designed for a pattern of testing wherein
the the app executes code and makes requests first. the app executes code and makes requests first.
Then a test expects that certain requests have or have not been made, Then a test expects that certain requests have or have not been made,
performs assertions against those requests, performs assertions against those requests,
@ -964,7 +964,7 @@ along with the other symbols your tests require.
<code-example <code-example
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="imports" region="imports"
title="app/testing/http-client.spec.ts (imports)" linenums="false"> header="app/testing/http-client.spec.ts (imports)" linenums="false">
</code-example> </code-example>
Then add the `HttpClientTestingModule` to the `TestBed` and continue with Then add the `HttpClientTestingModule` to the `TestBed` and continue with
@ -973,7 +973,7 @@ the setup of the _service-under-test_.
<code-example <code-example
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="setup" region="setup"
title="app/testing/http-client.spec.ts(setup)" linenums="false"> header="app/testing/http-client.spec.ts(setup)" linenums="false">
</code-example> </code-example>
Now requests made in the course of your tests will hit the testing backend instead of the normal backend. Now requests made in the course of your tests will hit the testing backend instead of the normal backend.
@ -988,7 +988,7 @@ Now you can write a test that expects a GET Request to occur and provides a mock
<code-example <code-example
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="get-test" region="get-test"
title="app/testing/http-client.spec.ts(httpClient.get)" linenums="false"> header="app/testing/http-client.spec.ts(httpClient.get)" linenums="false">
</code-example> </code-example>
The last step, verifying that no requests remain outstanding, is common enough for you to move it into an `afterEach()` step: The last step, verifying that no requests remain outstanding, is common enough for you to move it into an `afterEach()` step:

View File

@ -19,7 +19,7 @@ Angular simplifies the following aspects of internationalization:
* Handling plural forms of words. * Handling plural forms of words.
* Handling alternative text. * Handling alternative text.
For localization, you can use the [**Angular CLI**](https://cli.angular.io/) to generate most of the boilerplate necessary to create files for translators, and to publish your app in multiple languages. For localization, you can use the [Angular CLI](cli) to generate most of the boilerplate necessary to create files for translators, and to publish your app in multiple languages.
After you have set up your app to use i18n, the CLI can help you with the following steps: After you have set up your app to use i18n, the CLI can help you with the following steps:
* Extracting localizable text into a file that you can send out to be translated. * Extracting localizable text into a file that you can send out to be translated.
* Building and serving the app for a given locale, using the translated text. * Building and serving the app for a given locale, using the translated text.
@ -57,7 +57,7 @@ To set your app's locale to another value, use the CLI parameter `--configuratio
If you use JIT, you also need to define the `LOCALE_ID` provider in your main module: If you use JIT, you also need to define the `LOCALE_ID` provider in your main module:
<code-example path="i18n/doc-files/app.module.ts" title="src/app/app.module.ts" linenums="false"> <code-example path="i18n/doc-files/app.module.ts" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
@ -97,7 +97,7 @@ The CLI imports the locale data for you when you use the parameter `--configurat
If you want to import locale data for other languages, you can do it manually: If you want to import locale data for other languages, you can do it manually:
<code-example path="i18n/doc-files/app.locale_data.ts" region="import-locale" title="src/app/app.module.ts" linenums="false"> <code-example path="i18n/doc-files/app.locale_data.ts" region="import-locale" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
The first parameter is an object containing the locale data imported from `@angular/common/locales`. The first parameter is an object containing the locale data imported from `@angular/common/locales`.
@ -112,7 +112,7 @@ The files in `@angular/common/locales` contain most of the locale data that you
need, but some advanced formatting options might only be available in the extra dataset that you can need, but some advanced formatting options might only be available in the extra dataset that you can
import from `@angular/common/locales/extra`. An error message informs you when this is the case. import from `@angular/common/locales/extra`. An error message informs you when this is the case.
<code-example path="i18n/doc-files/app.locale_data_extra.ts" region="import-locale-extra" title="src/app/app.module.ts" linenums="false"> <code-example path="i18n/doc-files/app.locale_data_extra.ts" region="import-locale-extra" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -158,12 +158,12 @@ text is to be translated.
In the example below, an `<h1>` tag displays a simple English language greeting, "Hello i18n!" In the example below, an `<h1>` tag displays a simple English language greeting, "Hello i18n!"
<code-example path="i18n/doc-files/app.component.html" region="greeting" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="greeting" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag. To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag.
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="i18n-attribute" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -183,7 +183,7 @@ To translate a text message accurately, the translator may need additional infor
You can add a description of the text message as the value of the `i18n` attribute, as shown in the You can add a description of the text message as the value of the `i18n` attribute, as shown in the
example below: example below:
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-desc" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-desc" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The translator may also need to know the meaning or intent of the text message within this particular The translator may also need to know the meaning or intent of the text message within this particular
@ -192,7 +192,7 @@ app context.
You add context by beginning the `i18n` attribute value with the _meaning_ and You add context by beginning the `i18n` attribute value with the _meaning_ and
separating it from the _description_ with the `|` character: `<meaning>|<description>` separating it from the _description_ with the `|` character: `<meaning>|<description>`
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-meaning" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-meaning" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
All occurrences of a text message that have the same meaning will have the same translation. All occurrences of a text message that have the same meaning will have the same translation.
@ -220,7 +220,7 @@ You must then update the translation file with the new id.
Alternatively, you can specify a custom id in the `i18n` attribute by using the prefix `@@`. Alternatively, you can specify a custom id in the `i18n` attribute by using the prefix `@@`.
The example below defines the custom id `introductionHeader`: The example below defines the custom id `introductionHeader`:
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-solo-id' title='app/app.component.html' linenums="false"> <code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-solo-id' header='app/app.component.html' linenums="false">
</code-example> </code-example>
When you specify a custom id, the extractor tool and compiler generate a translation unit with that When you specify a custom id, the extractor tool and compiler generate a translation unit with that
@ -238,12 +238,12 @@ You can use a custom id in combination with a description by including both in t
`i18n` attribute. In the example below, the `i18n` attribute value includes a description, followed `i18n` attribute. In the example below, the `i18n` attribute value includes a description, followed
by the custom `id`: by the custom `id`:
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-id' title='app/app.component.html' linenums="false"> <code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-id' header='app/app.component.html' linenums="false">
</code-example> </code-example>
You also can add a meaning, as shown in this example: You also can add a meaning, as shown in this example:
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-meaning-and-id' title='app/app.component.html' linenums="false"> <code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-meaning-and-id' header='app/app.component.html' linenums="false">
</code-example> </code-example>
#### Define unique custom ids #### Define unique custom ids
@ -287,7 +287,7 @@ However, if you don't want to create a new DOM element merely to facilitate tran
you can wrap the text in an `<ng-container>` element. you can wrap the text in an `<ng-container>` element.
The `<ng-container>` is transformed into an html comment: The `<ng-container>` is transformed into an html comment:
<code-example path="i18n/src/app/app.component.html" region="i18n-ng-container" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-ng-container" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
{@a translate-attributes} {@a translate-attributes}
@ -296,14 +296,14 @@ The `<ng-container>` is transformed into an html comment:
Displayed text is sometimes supplied as the value of an attribute, rather than the content of tag. Displayed text is sometimes supplied as the value of an attribute, rather than the content of tag.
For example, if your template has an image with a `title` attribute, the text value of the `title` attribute needs to be translated. For example, if your template has an image with a `title` attribute, the text value of the `title` attribute needs to be translated.
<code-example path="i18n/doc-files/app.component.html" region="i18n-title" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="i18n-title" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
To mark an attribute for translation, add an attribute in the form of `i18n-x`, To mark an attribute for translation, add an attribute in the form of `i18n-x`,
where `x` is the name of the attribute to translate. The following example shows how to mark the where `x` is the name of the attribute to translate. The following example shows how to mark the
`title` attribute for translation by adding the `i18n-title` attribute on the `img` tag: `title` attribute for translation by adding the `i18n-title` attribute on the `img` tag:
<code-example path="i18n/src/app/app.component.html" region="i18n-title-translate" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-title-translate" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
This technique works for any attribute of any element. This technique works for any attribute of any element.
@ -328,7 +328,7 @@ Other languages might express the cardinality differently.
The example below shows how to use a `plural` ICU expression to display one of those three options The example below shows how to use a `plural` ICU expression to display one of those three options
based on when the update occurred: based on when the update occurred:
<code-example path="i18n/src/app/app.component.html" region="i18n-plural" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-plural" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
* The first parameter is the key. It is bound to the component property (`minutes`), which determines * The first parameter is the key. It is bound to the component property (`minutes`), which determines
@ -359,7 +359,7 @@ Pluralization categories include (depending on the language):
After the pluralization category, put the default English text in braces (`{}`). After the pluralization category, put the default English text in braces (`{}`).
In the example above, the three options are specified according to that pluralization pattern. For In the example above, the three options are specified according to that pluralization pattern. For
talking about about zero minutes, you use `=0 {just now}`. For one minute, you use `=1 {one minute}`. talking about zero minutes, you use `=0 {just now}`. For one minute, you use `=1 {one minute}`.
Any unmatched cardinality uses `other {{{minutes}} minutes ago}`. You could choose to add patterns Any unmatched cardinality uses `other {{{minutes}} minutes ago}`. You could choose to add patterns
for two, three, or any other number if the pluralization rules were different. For the example of for two, three, or any other number if the pluralization rules were different. For the example of
"minute", only these three patterns are necessary in English. "minute", only these three patterns are necessary in English.
@ -384,7 +384,7 @@ The following format message in the component template binds to the component's
which outputs one of the following string values: "m", "f" or "o". which outputs one of the following string values: "m", "f" or "o".
The message maps those values to the appropriate translations: The message maps those values to the appropriate translations:
<code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-select" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
{@a nesting-ICUS} {@a nesting-ICUS}
@ -392,7 +392,7 @@ The message maps those values to the appropriate translations:
You can also nest different ICU expressions together, as shown in this example: You can also nest different ICU expressions together, as shown in this example:
<code-example path="i18n/src/app/app.component.html" region="i18n-nested" title="src/app/app.component.html"> <code-example path="i18n/src/app/app.component.html" region="i18n-nested" header="src/app/app.component.html">
</code-example> </code-example>
{@a ng-xi18n} {@a ng-xi18n}
@ -413,7 +413,7 @@ By default, the command creates a file named `messages.xlf` in your `src/` folde
If you don't use the CLI, you have two options: If you don't use the CLI, you have two options:
* You can use the `ng-xi18n` tool directly from the `@angular/compiler-cli` package. * You can use the `ng-xi18n` tool directly from the `@angular/compiler-cli` package.
For more information, see [i18n in the CLI documentation](https://github.com/angular/angular-cli/wiki/xi18n). For more information, see the [`ng xi18n` command documentation](cli/xi18n).
* You can use the CLI Webpack plugin `AngularCompilerPlugin` from the `@ngtools/webpack` package. * You can use the CLI Webpack plugin `AngularCompilerPlugin` from the `@ngtools/webpack` package.
Set the parameters `i18nOutFile` and `i18nOutFormat` to trigger the extraction. Set the parameters `i18nOutFile` and `i18nOutFormat` to trigger the extraction.
For more information, see the [Angular Ahead-of-Time Webpack Plugin documentation](https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack). For more information, see the [Angular Ahead-of-Time Webpack Plugin documentation](https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack).
@ -530,7 +530,7 @@ This sample file is easy to translate without a special editor or knowledge of F
1. Open `messages.fr.xlf` and find the first `<trans-unit>` section: 1. Open `messages.fr.xlf` and find the first `<trans-unit>` section:
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello-before" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> > <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello-before" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
> This XML element represents the translation of the `<h1>` greeting tag that you marked with the > This XML element represents the translation of the `<h1>` greeting tag that you marked with the
@ -542,16 +542,16 @@ This sample file is easy to translate without a special editor or knowledge of F
2. Duplicate the `<source/>` tag, rename it `target`, and then replace its content with the French 2. Duplicate the `<source/>` tag, rename it `target`, and then replace its content with the French
greeting. If you were working with a more complex translation, you could use the the information greeting. If you were working with a more complex translation, you could use the information
and context provided by the source, description, and meaning elements to guide your selection of and context provided by the source, description, and meaning elements to guide your selection of
the appropriate French translation. the appropriate French translation.
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;, after translation)" linenums="false"> > <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;, after translation)" linenums="false">
</code-example> </code-example>
3. Translate the other text nodes the same way: 3. Translate the other text nodes the same way:
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-other-nodes" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> > <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-other-nodes" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
<div class="alert is-important"> <div class="alert is-important">
@ -578,7 +578,7 @@ must be just below the translation unit for the logo.
To translate a `plural`, translate its ICU format match values: To translate a `plural`, translate its ICU format match values:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-plural" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-plural" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
You can add or remove plural cases, with each language having its own cardinality. (See You can add or remove plural cases, with each language having its own cardinality. (See
@ -589,7 +589,7 @@ You can add or remove plural cases, with each language having its own cardinalit
Below is the content of our example `select` ICU expression in the component template: Below is the content of our example `select` ICU expression in the component template:
<code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-select" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The extraction tool broke that into two translation units because ICU expressions are extracted The extraction tool broke that into two translation units because ICU expressions are extracted
@ -600,18 +600,18 @@ In place of the `select` is a placeholder, `<x id="ICU">`, that represents the `
Translate the text and move around the placeholder if necessary, but don't remove it. If you remove Translate the text and move around the placeholder if necessary, but don't remove it. If you remove
the placeholder, the ICU expression will not be present in your translated app. the placeholder, the ICU expression will not be present in your translated app.
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-1" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-1" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
The second translation unit, immediately below the first one, contains the `select` message. The second translation unit, immediately below the first one, contains the `select` message.
Translate that as well. Translate that as well.
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-2" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-2" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
Here they are together, after translation: Here they are together, after translation:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-select" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-select" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
{@a translate-nested} {@a translate-nested}
@ -620,17 +620,17 @@ Here they are together, after translation:
A nested expression is similar to the previous examples. As in the previous example, there are A nested expression is similar to the previous examples. As in the previous example, there are
two translation units. The first one contains the text outside of the nested expression: two translation units. The first one contains the text outside of the nested expression:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-1" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-1" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
The second unit contains the complete nested expression: The second unit contains the complete nested expression:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-2" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-2" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
And both together: And both together:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested" header="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
The entire template translation is complete. The next section describes how to load that translation The entire template translation is complete. The next section describes how to load that translation
@ -642,15 +642,15 @@ into the app.
The sample app and its translation file are now as follows: The sample app and its translation file are now as follows:
<code-tabs> <code-tabs>
<code-pane title="src/app/app.component.html" path="i18n/src/app/app.component.html"> <code-pane header="src/app/app.component.html" path="i18n/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane title="src/app/app.component.ts" path="i18n/src/app/app.component.ts"> <code-pane header="src/app/app.component.ts" path="i18n/src/app/app.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/app.module.ts" path="i18n/src/app/app.module.ts"> <code-pane header="src/app/app.module.ts" path="i18n/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="src/main.ts" path="i18n/doc-files/main.1.ts"> <code-pane header="src/main.ts" path="i18n/doc-files/main.1.ts">
</code-pane> </code-pane>
<code-pane title="src/locale/messages.fr.xlf" path="i18n/doc-files/messages.fr.xlf.html"> <code-pane header="src/locale/messages.fr.xlf" path="i18n/doc-files/messages.fr.xlf.html">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
@ -672,7 +672,7 @@ format that Angular understands, such as `.xtb`.
How you provide this information depends upon whether you compile with How you provide this information depends upon whether you compile with
the JIT compiler or the AOT compiler. the JIT compiler or the AOT compiler.
* With [AOT](guide/i18n#merge-aot), you pass the information as a configuration * With [AOT](guide/i18n#merge-aot), you pass the information as configuration settings.
* With [JIT](guide/i18n#merge-jit), you provide the information at bootstrap time. * With [JIT](guide/i18n#merge-jit), you provide the information at bootstrap time.
@ -790,12 +790,12 @@ while compiling the app:
The Angular `bootstrapModule` method has a second `compilerOptions` parameter that can influence the The Angular `bootstrapModule` method has a second `compilerOptions` parameter that can influence the
behavior of the compiler. You can use it to specify the translation providers: behavior of the compiler. You can use it to specify the translation providers:
<code-example path="i18n/doc-files/main.2.ts" title="src/main.ts"> <code-example path="i18n/doc-files/main.2.ts" header="src/main.ts">
</code-example> </code-example>
Then provide the `LOCALE_ID` in the main module: Then provide the `LOCALE_ID` in the main module:
<code-example path="i18n/doc-files/app.module.ts" title="src/app/app.module.ts" linenums="false"> <code-example path="i18n/doc-files/app.module.ts" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
@ -826,7 +826,7 @@ If you use the JIT compiler, specify the warning level in the compiler config at
the 'MissingTranslationStrategy' property. The example below shows how to set the warning level to the 'MissingTranslationStrategy' property. The example below shows how to set the warning level to
error: error:
<code-example path="i18n/doc-files/main.3.ts" title="src/main.ts"> <code-example path="i18n/doc-files/main.3.ts" header="src/main.ts">
</code-example> </code-example>
### Build for multiple locales ### Build for multiple locales

View File

@ -98,7 +98,7 @@ placeholder markup in `app.component.html` with a custom nav
so you can easily navigate to your modules in the browser: so you can easily navigate to your modules in the browser:
<code-example path="lazy-loading-ngmodules/src/app/app.component.html" region="app-component-template" title="src/app/app.component.html" linenums="false"> <code-example path="lazy-loading-ngmodules/src/app/app.component.html" region="app-component-template" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -138,19 +138,19 @@ Each feature module acts as a doorway via the router. In the `AppRoutingModule`,
In `AppRoutingModule`, update the `routes` array with the following: In `AppRoutingModule`, update the `routes` array with the following:
<code-example path="lazy-loading-ngmodules/src/app/app-routing.module.ts" region="const-routes" title="src/app/app-routing.module.ts" linenums="false"> <code-example path="lazy-loading-ngmodules/src/app/app-routing.module.ts" region="const-routes" header="src/app/app-routing.module.ts" linenums="false">
</code-example> </code-example>
The import statements stay the same. The first two paths are the routes to the `CustomersModule` and the `OrdersModule` respectively. Notice that the lazy loading syntax uses `loadChildren` followed by a string that is the path to the module, a hash mark or `#`, and the modules class name. The import statements stay the same. The first two paths are the routes to the `CustomersModule` and the `OrdersModule` respectively. Notice that the lazy loading syntax uses `loadChildren` followed by a string that is the relative path to the module, a hash mark or `#`, and the modules class name.
### Inside the feature module ### Inside the feature module
Next, take a look at `customers.module.ts`. If youre using the CLI and following the steps outlined in this page, you dont have to do anything here. The feature module is like a connector between the `AppRoutingModule` and the feature routing module. The `AppRoutingModule` imports the feature module, `CustomersModule`, and `CustomersModule` in turn imports the `CustomersRoutingModule`. Next, take a look at `customers.module.ts`. If youre using the CLI and following the steps outlined in this page, you dont have to do anything here. The feature module is like a connector between the `AppRoutingModule` and the feature routing module. The `AppRoutingModule` imports the feature module, `CustomersModule`, and `CustomersModule` in turn imports the `CustomersRoutingModule`.
<code-example path="lazy-loading-ngmodules/src/app/customers/customers.module.ts" region="customers-module" title="src/app/customers/customers.module.ts" linenums="false"> <code-example path="lazy-loading-ngmodules/src/app/customers/customers.module.ts" region="customers-module" header="src/app/customers/customers.module.ts" linenums="false">
</code-example> </code-example>
@ -163,7 +163,7 @@ The `customers.module.ts` file imports the `CustomersRoutingModule` and `Custome
The next step is in `customers-routing.module.ts`. First, import the component at the top of the file with the other JavaScript import statements. Then, add the route to `CustomerListComponent`. The next step is in `customers-routing.module.ts`. First, import the component at the top of the file with the other JavaScript import statements. Then, add the route to `CustomerListComponent`.
<code-example path="lazy-loading-ngmodules/src/app/customers/customers-routing.module.ts" region="customers-routing-module" title="src/app/customers/customers-routing.module.ts" linenums="false"> <code-example path="lazy-loading-ngmodules/src/app/customers/customers-routing.module.ts" region="customers-routing-module" header="src/app/customers/customers-routing.module.ts" linenums="false">
</code-example> </code-example>
@ -172,7 +172,7 @@ Notice that the `path` is set to an empty string. This is because the path in `A
Repeat this last step of importing the `OrdersListComponent` and configuring the Routes array for the `orders-routing.module.ts`: Repeat this last step of importing the `OrdersListComponent` and configuring the Routes array for the `orders-routing.module.ts`:
<code-example path="lazy-loading-ngmodules/src/app/orders/orders-routing.module.ts" region="orders-routing-module-detail" title="src/app/orders/orders-routing.module.ts (excerpt)" linenums="false"> <code-example path="lazy-loading-ngmodules/src/app/orders/orders-routing.module.ts" region="orders-routing-module-detail" header="src/app/orders/orders-routing.module.ts (excerpt)" linenums="false">
</code-example> </code-example>

View File

@ -23,7 +23,7 @@ Each interface has a single hook method whose name is the interface name prefixe
For example, the `OnInit` interface has a hook method named `ngOnInit()` For example, the `OnInit` interface has a hook method named `ngOnInit()`
that Angular calls shortly after creating the component: that Angular calls shortly after creating the component:
<code-example path="lifecycle-hooks/src/app/peek-a-boo.component.ts" region="ngOnInit" title="peek-a-boo.component.ts (excerpt)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/peek-a-boo.component.ts" region="ngOnInit" header="peek-a-boo.component.ts (excerpt)" linenums="false"></code-example>
No directive or component will implement all of the lifecycle hooks. No directive or component will implement all of the lifecycle hooks.
Angular only calls a directive/component hook method *if it is defined*. Angular only calls a directive/component hook method *if it is defined*.
@ -339,13 +339,13 @@ The heroes will never know they're being watched.
The sneaky spy directive is simple, consisting almost entirely of `ngOnInit()` and `ngOnDestroy()` hooks The sneaky spy directive is simple, consisting almost entirely of `ngOnInit()` and `ngOnDestroy()` hooks
that log messages to the parent via an injected `LoggerService`. that log messages to the parent via an injected `LoggerService`.
<code-example path="lifecycle-hooks/src/app/spy.directive.ts" region="spy-directive" title="src/app/spy.directive.ts" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/spy.directive.ts" region="spy-directive" header="src/app/spy.directive.ts" linenums="false"></code-example>
You can apply the spy to any native or component element and it'll be initialized and destroyed You can apply the spy to any native or component element and it'll be initialized and destroyed
at the same time as that element. at the same time as that element.
Here it is attached to the repeated hero `<div>`: Here it is attached to the repeated hero `<div>`:
<code-example path="lifecycle-hooks/src/app/spy.component.html" region="template" title="src/app/spy.component.html" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/spy.component.html" region="template" header="src/app/spy.component.html" linenums="false"></code-example>
Each spy's birth and death marks the birth and death of the attached hero `<div>` Each spy's birth and death marks the birth and death of the attached hero `<div>`
with an entry in the *Hook Log* as seen here: with an entry in the *Hook Log* as seen here:
@ -425,7 +425,7 @@ You risk memory leaks if you neglect to do so.
Angular calls its `ngOnChanges()` method whenever it detects changes to ***input properties*** of the component (or directive). Angular calls its `ngOnChanges()` method whenever it detects changes to ***input properties*** of the component (or directive).
This example monitors the `OnChanges` hook. This example monitors the `OnChanges` hook.
<code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="ng-on-changes" title="on-changes.component.ts (excerpt)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="ng-on-changes" header="on-changes.component.ts (excerpt)" linenums="false"></code-example>
The `ngOnChanges()` method takes an object that maps each changed property name to a The `ngOnChanges()` method takes an object that maps each changed property name to a
[SimpleChange](api/core/SimpleChange) object holding the current and previous property values. [SimpleChange](api/core/SimpleChange) object holding the current and previous property values.
@ -433,11 +433,11 @@ This hook iterates over the changed properties and logs them.
The example component, `OnChangesComponent`, has two input properties: `hero` and `power`. The example component, `OnChangesComponent`, has two input properties: `hero` and `power`.
<code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="inputs" title="src/app/on-changes.component.ts" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="inputs" header="src/app/on-changes.component.ts" linenums="false"></code-example>
The host `OnChangesParentComponent` binds to them like this: The host `OnChangesParentComponent` binds to them like this:
<code-example path="lifecycle-hooks/src/app/on-changes-parent.component.html" region="on-changes" title="src/app/on-changes-parent.component.html"></code-example> <code-example path="lifecycle-hooks/src/app/on-changes-parent.component.html" region="on-changes" header="src/app/on-changes-parent.component.html"></code-example>
Here's the sample in action as the user makes changes. Here's the sample in action as the user makes changes.
@ -468,7 +468,7 @@ Use the `DoCheck` hook to detect and act upon changes that Angular doesn't catch
The *DoCheck* sample extends the *OnChanges* sample with the following `ngDoCheck()` hook: The *DoCheck* sample extends the *OnChanges* sample with the following `ngDoCheck()` hook:
<code-example path="lifecycle-hooks/src/app/do-check.component.ts" region="ng-do-check" title="DoCheckComponent (ngDoCheck)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/do-check.component.ts" region="ng-do-check" header="DoCheckComponent (ngDoCheck)" linenums="false"></code-example>
This code inspects certain _values of interest_, capturing and comparing their current state against previous values. This code inspects certain _values of interest_, capturing and comparing their current state against previous values.
It writes a special message to the log when there are no substantive changes to the `hero` or the `power` It writes a special message to the log when there are no substantive changes to the `hero` or the `power`
@ -497,25 +497,25 @@ The *AfterView* sample explores the `AfterViewInit()` and `AfterViewChecked()` h
Here's a child view that displays a hero's name in an `<input>`: Here's a child view that displays a hero's name in an `<input>`:
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="child-view" title="ChildComponent" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="child-view" header="ChildComponent" linenums="false"></code-example>
The `AfterViewComponent` displays this child view *within its template*: The `AfterViewComponent` displays this child view *within its template*:
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="template" title="AfterViewComponent (template)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="template" header="AfterViewComponent (template)" linenums="false"></code-example>
The following hooks take action based on changing values *within the child view*, The following hooks take action based on changing values *within the child view*,
which can only be reached by querying for the child view via the property decorated with which can only be reached by querying for the child view via the property decorated with
[@ViewChild](api/core/ViewChild). [@ViewChild](api/core/ViewChild).
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="hooks" title="AfterViewComponent (class excerpts)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="hooks" header="AfterViewComponent (class excerpts)" linenums="false"></code-example>
{@a wait-a-tick} {@a wait-a-tick}
### Abide by the unidirectional data flow rule ### Abide by the unidirectional data flow rule
The `doSomething()` method updates the screen when the hero name exceeds 10 characters. The `doSomething()` method updates the screen when the hero name exceeds 10 characters.
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="do-something" title="AfterViewComponent (doSomething)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="do-something" header="AfterViewComponent (doSomething)" linenums="false"></code-example>
Why does the `doSomething()` method wait a tick before updating `comment`? Why does the `doSomething()` method wait a tick before updating `comment`?
@ -559,7 +559,7 @@ Consider this variation on the [previous _AfterView_](guide/lifecycle-hooks#afte
This time, instead of including the child view within the template, it imports the content from This time, instead of including the child view within the template, it imports the content from
the `AfterContentComponent`'s parent. Here's the parent's template: the `AfterContentComponent`'s parent. Here's the parent's template:
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="parent-template" title="AfterContentParentComponent (template excerpt)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="parent-template" header="AfterContentParentComponent (template excerpt)" linenums="false"></code-example>
Notice that the `<app-child>` tag is tucked between the `<after-content>` tags. Notice that the `<app-child>` tag is tucked between the `<after-content>` tags.
Never put content between a component's element tags *unless you intend to project that content Never put content between a component's element tags *unless you intend to project that content
@ -567,7 +567,7 @@ into the component*.
Now look at the component's template: Now look at the component's template:
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="template" title="AfterContentComponent (template)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="template" header="AfterContentComponent (template)" linenums="false"></code-example>
The `<ng-content>` tag is a *placeholder* for the external content. The `<ng-content>` tag is a *placeholder* for the external content.
It tells Angular where to insert that content. It tells Angular where to insert that content.
@ -603,7 +603,7 @@ The following *AfterContent* hooks take action based on changing values in a *co
which can only be reached by querying for them via the property decorated with which can only be reached by querying for them via the property decorated with
[@ContentChild](api/core/ContentChild). [@ContentChild](api/core/ContentChild).
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="hooks" title="AfterContentComponent (class excerpts)" linenums="false"></code-example> <code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="hooks" header="AfterContentComponent (class excerpts)" linenums="false"></code-example>
{@a no-unidirectional-flow-worries} {@a no-unidirectional-flow-worries}

View File

@ -480,7 +480,7 @@ You can throw an error or take other remedial action.
Certain NgModules, such as `BrowserModule`, implement such a guard. Certain NgModules, such as `BrowserModule`, implement such a guard.
Here is a custom constructor for an NgModule called `CoreModule`. Here is a custom constructor for an NgModule called `CoreModule`.
<code-example path="ngmodule-faq/src/app/core/core.module.ts" region="ctor" title="src/app/core/core.module.ts (Constructor)" linenums="false"> <code-example path="ngmodule-faq/src/app/core/core.module.ts" region="ctor" header="src/app/core/core.module.ts (Constructor)" linenums="false">
</code-example> </code-example>
<hr/> <hr/>

View File

@ -29,7 +29,7 @@ JavaScript modules help you namespace, preventing accidental global variables.
<!-- KW-- perMisko: let's discuss. This does not answer the question why it is different. Also, last sentence is confusing.--> <!-- KW-- perMisko: let's discuss. This does not answer the question why it is different. Also, last sentence is confusing.-->
NgModules are classes decorated with `@NgModule`. The `@NgModule` decorators `imports` array tells Angular what other NgModules the current module needs. The modules in the `imports` array are different than JavaScript modules because they are NgModules rather than regular JavaScript modules. Classes with an `@NgModule` decorator are by convention kept in their own files, but what makes them an `NgModule` isnt being in their own file, like JavaScript modules; its the presence of `@NgModule` and its metadata. NgModules are classes decorated with `@NgModule`. The `@NgModule` decorators `imports` array tells Angular what other NgModules the current module needs. The modules in the `imports` array are different than JavaScript modules because they are NgModules rather than regular JavaScript modules. Classes with an `@NgModule` decorator are by convention kept in their own files, but what makes them an `NgModule` isnt being in their own file, like JavaScript modules; its the presence of `@NgModule` and its metadata.
The `AppModule` generated from the Angular CLI demonstrates both kinds of modules in action: The `AppModule` generated from the [Angular CLI](cli) demonstrates both kinds of modules in action:
```typescript ```typescript
/* These are JavaScript import statements. Angular doesnt know anything about these. */ /* These are JavaScript import statements. Angular doesnt know anything about these. */

View File

@ -57,9 +57,9 @@ You then import these modules into the root module.
## The basic NgModule ## The basic NgModule
The CLI generates the following basic app module when creating a new app. The [Angular CLI](cli) generates the following basic app module when creating a new app.
<code-example path="bootstrapping/src/app/app.module.ts" region="whole-ngmodule" title="src/app/app.module.ts" linenums="false"> <code-example path="bootstrapping/src/app/app.module.ts" region="whole-ngmodule" header="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
At the top are the import statements. The next section is where you configure the `@NgModule` by stating what components and directives belong to it (`declarations`) as well as which other modules it uses (`imports`). This page builds on [Bootstrapping](guide/bootstrapping), which covers the structure of an NgModule in detail. If you need more information on the structure of an `@NgModule`, be sure to read [Bootstrapping](guide/bootstrapping). At the top are the import statements. The next section is where you configure the `@NgModule` by stating what components and directives belong to it (`declarations`) as well as which other modules it uses (`imports`). This page builds on [Bootstrapping](guide/bootstrapping), which covers the structure of an NgModule in detail. If you need more information on the structure of an `@NgModule`, be sure to read [Bootstrapping](guide/bootstrapping).

View File

@ -1,173 +1,141 @@
# Npm Packages # Workspace npm dependencies
The [**Angular CLI**](https://cli.angular.io/), Angular applications, and Angular itself depend upon features and functionality provided by libraries that are available as [**npm**](https://docs.npmjs.com/) packages. The Angular Framework, Angular CLI, and components used by Angular applications are packaged as [npm packages](https://docs.npmjs.com/getting-started/what-is-npm "What is npm?") and distributed via the [npm registry](https://docs.npmjs.com/).
You can download and install these npm packages with the [**npm client**](https://docs.npmjs.com/cli/install), which runs as a Node.js® application. You can download and install these npm packages by using the [npm CLI client](https://docs.npmjs.com/cli/install), which is installed with and runs as a [Node.js®](https://nodejs.org "Nodejs.org") application. By default, the Angular CLI uses the npm client.
Alternatively, you can use the [yarn client](https://yarnpkg.com/) for downloading and installing npm packages.
The [**yarn client**](https://yarnpkg.com/en/) is a popular alternative for downloading and installing npm packages.
The Angular CLI uses `yarn` by default to install npm packages when you create a new project.
<div class="alert is-helpful"> <div class="alert is-helpful">
Node.js and npm are essential to Angular development. See [Getting Started](guide/quickstart#prerequisites) for information about the required versions and installation of Node.js and npm.
[Get them now](https://docs.npmjs.com/getting-started/installing-node "Installing Node.js and updating npm") If you already have projects running on your machine that use other versions of Node.js and npm, consider using [nvm](https://github.com/creationix/nvm) to manage the multiple versions of Node.js and npm.
if they're not already installed on your machine.
**Verify that you are running Node.js `v8.x` or higher and npm `5.x` or higher**
by running the commands `node -v` and `npm -v` in a terminal/console window.
Older versions produce errors.
Consider using [nvm](https://github.com/creationix/nvm) for managing multiple
versions of Node.js and npm. You may need [nvm](https://github.com/creationix/nvm) if
you already have projects running on your machine that use other versions of Node.js and npm.
</div> </div>
## _package.json_
Both `npm` and `yarn` install packages that are identified in a [**package.json**](https://docs.npmjs.com/files/package.json) file. ## `package.json`
The CLI `ng new` command creates a default `package.json` file for your project. Both `npm` and `yarn` install the packages that are identified in a [`package.json`](https://docs.npmjs.com/files/package.json) file.
This `package.json` specifies _a starter set of packages_ that work well together and
jointly support many common application scenarios.
You will add packages to `package.json` as your application evolves. The CLI command `ng new` creates a `package.json` file when it creates the new workspace.
You may even remove some. This `package.json` is used by all projects in the workspace, including the initial app project that is created by the CLI when it creates the workspace.
This guide focuses on the most important packages in the starter set. Initially, this `package.json` includes _a starter set of packages_, some of which are required by Angular and others that support common application scenarios.
You add packages to `package.json` as your application evolves.
You may even remove some.
#### *dependencies* and *devDependencies* The `package.json` is organized into two groups of packages:
The `package.json` includes two sets of packages, * [Dependencies](guide/npm-packages#dependencies) are essential to *running* applications.
[dependencies](guide/npm-packages#dependencies) and [devDependencies](guide/npm-packages#dev-dependencies). * [DevDependencies](guide/npm-packages#dev-dependencies) are only necessary to *develop* applications.
<div class="alert is-helpful">
**Library developers:** By default, the CLI command [`ng generate library`](cli/generate) creates a `package.json` for the new library. That `package.json` is used when publishing the library to npm.
For more information, see the CLI wiki page [Library Support](https://github.com/angular/angular-cli/wiki/stories-create-library).
</div>
The *dependencies* are essential to *running* the application.
The *devDependencies* are only necessary to *develop* the application.
{@a dependencies} {@a dependencies}
## Dependencies
The packages listed in the `dependencies` section of `package.json` are essential to *running* applications.
## *Dependencies*
The `dependencies` section of `package.json` contains: The `dependencies` section of `package.json` contains:
* **Angular packages**: Angular core and optional modules; their package names begin `@angular/`. * [**Angular packages**](#angular-packages): Angular core and optional modules; their package names begin `@angular/`.
* **Support packages**: 3rd party libraries that must be present for Angular apps to run. * [**Support packages**](#support-packages): 3rd party libraries that must be present for Angular apps to run.
* **Polyfill packages**: Polyfills plug gaps in a browser's JavaScript implementation. * [**Polyfill packages**](#polyfills): Polyfills plug gaps in a browser's JavaScript implementation.
### Angular Packages To add a new dependency, use the [`ng add`](cli/add) command.
**@angular/animations**: Angular's animations library makes it easy to define and apply animation effects such as page and list transitions. {@a angular-packages}
Read about it in the [Animations guide](guide/animations). ### Angular packages
**@angular/common**: The commonly needed services, pipes, and directives provided by the Angular team. The following Angular packages are included as dependencies in the default `package.json` file for a new Angular workspace.
The [`HttpClientModule`](guide/http) is also here, in the '@angular/common/http' subfolder. For a complete list of Angular packages, see the [API reference](http://angular.io/api?type=package).
**@angular/core**: Critical runtime parts of the framework needed by every application. Package name | Description
Includes all metadata decorators, `Component`, `Directive`, dependency injection, and the component lifecycle hooks. ---------------------------------------- | --------------------------------------------------
[**@angular/animations**](api/animations) | Angular's animations library makes it easy to define and apply animation effects such as page and list transitions. For more information, see the [Animations guide](guide/animations).
[**@angular/common**](api/common) | The commonly-needed services, pipes, and directives provided by the Angular team. The [`HttpClientModule`](api/common/http/HttpClientModule) is also here, in the [`@angular/common/http`](api/common/http) subfolder. For more information, see the [HttpClient guide](guide/http).
**@angular/compiler** | Angular's template compiler. It understands templates and can convert them to code that makes the application run and render. Typically you dont interact with the compiler directly; rather, you use it indirectly via `platform-browser-dynamic` when JIT compiling in the browser. For more information, see the [Ahead-of-time Compilation guide](guide/aot-compiler).
[**@angular/core**](api/core) | Critical runtime parts of the framework that are needed by every application. Includes all metadata decorators, `Component`, `Directive`, dependency injection, and the component lifecycle hooks.
[**@angular/forms**](api/forms) | Support for both [template-driven](guide/forms) and [reactive forms](guide/reactive-forms). For information about choosing the best forms approach for your app, see [Introduction to forms](guide/forms-overview).
[**@angular/http**](api/http) | Angular's legacy HTTP client, which was deprecated in version 5.0 in favor of [@angular/common/http](api/common/http).
[**@angular/<br />platform&#8209;browser**](api/platform-browser) | Everything DOM and browser related, especially the pieces that help render into the DOM. This package also includes the `bootstrapModuleFactory()` method for bootstrapping applications for production builds that pre-compile with [AOT](guide/aot-compiler).
[**@angular/<br />platform&#8209;browser&#8209;dynamic**](api/platform-browser-dynamic) | Includes [providers](api/core/Provider) and methods to compile and run the app on the client using the [JIT compiler](guide/aot-compiler).
[**@angular/router**](api/router) | The router module navigates among your app pages when the browser URL changes. For more information, see [Routing and Navigation](guide/router).
**@angular/compiler**: Angular's *Template Compiler*.
It understands templates and can convert them to code that makes the application run and render.
Typically you dont interact with the compiler directly; rather, you use it indirectly via `platform-browser-dynamic` when [JIT compiling](guide/aot-compiler) in the browser.
**@angular/forms**: support for both [template-driven](guide/forms) and [reactive forms](guide/reactive-forms). {@a support-packages}
### Support packages
**@angular/http**: Angular's old, deprecated, HTTP client. The following support packages are included as dependencies in the default `package.json` file for a new Angular workspace.
**@angular/platform-browser**: Everything DOM and browser related, especially
the pieces that help render into the DOM.
This package also includes the `bootstrapModuleFactory()` method
for bootstrapping applications for production builds that pre-compile with [AOT](guide/aot-compiler).
**@angular/platform-browser-dynamic**: Includes [Providers](api/core/Provider) Package name | Description
and methods to compile and run the app on the client ---------------------------------------- | --------------------------------------------------
using the [JIT compiler](guide/aot-compiler). [**rxjs**](https://github.com/ReactiveX/rxjs) | Many Angular APIs return [_observables_](guide/glossary#observable). RxJS is an implementation of the proposed [Observables specification](https://github.com/zenparsing/es-observable) currently before the [TC39](http://www.ecma-international.org/memento/TC39.htm) committee, which determines standards for the JavaScript language.
[**zone.js**](https://github.com/angular/zone.js) | Angular relies on zone.js to run Angular's change detection processes when native JavaScript operations raise events. Zone.js is an implementation of a [specification](https://gist.github.com/mhevery/63fdcdf7c65886051d55) currently before the [TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
**@angular/router**: The [router module](/guide/router) navigates among your app pages when the browser URL changes.
**@angular/upgrade**: Set of utilities for upgrading AngularJS applications to Angular.
{@a polyfills} {@a polyfills}
### Polyfill packages ### Polyfill packages
Many browsers lack native support for some features in the latest HTML standards, Many browsers lack native support for some features in the latest HTML standards,
features that Angular requires. features that Angular requires.
"[Polyfills](https://en.wikipedia.org/wiki/Polyfill)" can emulate the missing features. [_Polyfills_](https://en.wikipedia.org/wiki/Polyfill) can emulate the missing features.
The [Browser Support](guide/browser-support) guide explains which browsers need polyfills and The [Browser Support](guide/browser-support) guide explains which browsers need polyfills and
how you can add them. how you can add them.
The default `package.json` installs the **[core-js](https://github.com/zloirock/core-js)** package The `package.json` for a new Angular workspace installs the [core-js](https://github.com/zloirock/core-js) package,
which polyfills missing features for several popular browser. which polyfills missing features for several popular browser.
### Support packages
**[rxjs](https://github.com/benlesh/RxJS)**: Many Angular APIs return _observables_. RxJS is an implementation of the proposed [Observables specification](https://github.com/zenparsing/es-observable) currently before the
[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
**[zone.js](https://github.com/angular/zone.js)**: Angular relies on zone.js to run Angular's change detection processes when native JavaScript operations raise events. Zone.js is an implementation of a [specification](https://gist.github.com/mhevery/63fdcdf7c65886051d55) currently before the
[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
{@a dev-dependencies} {@a dev-dependencies}
## *DevDependencies* ## DevDependencies
The packages listed in the *devDependencies* section of the `package.json` help you develop the application on your local machine. The packages listed in the `devDependencies` section of `package.json` help you develop the application on your local machine. You don't deploy them with the production application.
You don't deploy them with the production application although there is no harm in doing so. To add a new `devDependency`, use either one of the following commands:
**[@angular/cli](https://github.com/angular/angular-cli/)**: The Angular CLI tools. <code-example language="sh" class="code-shell">
npm install --dev &lt;package-name&gt;
</code-example>
<code-example language="sh" class="code-shell">
yarn add --dev &lt;package-name&gt;
</code-example>
The following `devDependencies` are provided in the default `package.json` file for a new Angular workspace.
**[@angular/compiler-cli](https://github.com/angular/angular/blob/master/packages/compiler-cli/README.md)**: The Angular compiler, which is invoked by the Angular CLI's `build` and `serve` commands. Package name | Description
---------------------------------------- | -----------------------------------
[**@angular&#8209;devkit/<br />build&#8209;angular**](https://github.com/angular/angular-cli/) | The Angular build tools.
[**@angular/cli**](https://github.com/angular/angular-cli/) | The Angular CLI tools.
**@angular/<br />compiler&#8209;cli** | The Angular compiler, which is invoked by the Angular CLI's `ng build` and `ng serve` commands.
**@angular/<br />language&#8209;service** | The [Angular language service](guide/language-service) analyzes component templates and provides type and error information that TypeScript-aware editors can use to improve the developer's experience. For example, see the [Angular language service extension for VS Code](https://marketplace.visualstudio.com/items?itemName=Angular.ng-template).
**@types/... ** | TypeScript definition files for 3rd party libraries such as Jasmine and Node.js.
[**codelyzer**](https://www.npmjs.com/package/codelyzer) | A linter for Angular apps whose rules conform to the Angular [style guide](guide/styleguide).
**jasmine/... ** | Packages to support the [Jasmine](https://jasmine.github.io/) test library.
**karma/... ** | Packages to support the [karma](https://www.npmjs.com/package/karma) test runner.
[**protractor**](https://www.npmjs.com/package/protractor) | An end-to-end (e2e) framework for Angular apps. Built on top of [WebDriverJS](https://github.com/SeleniumHQ/selenium/wiki/WebDriverJs).
[**ts-node**](https://www.npmjs.com/package/ts-node) | TypeScript execution environment and REPL for Node.js.
[**tslint**](https://www.npmjs.com/package/tslint) | A static analysis tool that checks TypeScript code for readability, maintainability, and functionality errors.
[**typescript**](https://www.npmjs.com/package/typescript) | The TypeScript language server, including the *tsc* TypeScript compiler.
**[@angular/language-service](https://github.com/angular/angular-cli/)**: The Angular language service analyzes component templates and provides type and error information that TypeScript-aware editors can use to improve the developer's experience. ## Related information
For example, see the [Angular language service extension for VS Code](https://marketplace.visualstudio.com/items?itemName=Angular.ng-template)
For information about how the Angular CLI handles packages see the following guides:
**@types/... **: TypeScript definition files for 3rd party libraries such as Jasmine and Node.js.
* [Building and serving](guide/build) describes how packages come together to create a development build.
* [Deployment](guide/deployment) describes how packages come together to create a production build.
**[codelyzer](https://www.npmjs.com/package/codelyzer)**: A linter for Angular apps whose rules conform to the Angular [style guide](guide/styleguide).
**jasmine/... **: packages to support the [Jasmine](https://jasmine.github.io/) test library.
**karma/... **: packages to support the [karma](https://www.npmjs.com/package/karma) test runner.
**[protractor](https://www.npmjs.com/package/protractor)**: an end-to-end (e2e) framework for Angular apps.
Built on top of [WebDriverJS](https://github.com/SeleniumHQ/selenium/wiki/WebDriverJs).
**[ts-node](https://www.npmjs.com/package/ts-node)**: TypeScript execution environment and REPL for Node.js.
**[tslint](https://www.npmjs.com/package/tslint)**: a static analysis tool that checks TypeScript code for readability, maintainability, and functionality errors.
**[typescript](https://www.npmjs.com/package/typescript)**:
the TypeScript language server, including the *tsc* TypeScript compiler.
## So many packages! So many files!
The default `package.json` installs more packages than you'll need for your project.
A given package may contain tens, hundreds, even thousands of files,
all of them in your local machine's `node_modules` directory.
The sheer volume of files is intimidating,
You can remove packages that you don't need but how can you be sure that you won't need it?
As a practical matter, it's better to install a package you don't need than worry about it.
Extra packages and package files on your local development machine are harmless.
By default the Angular CLI build process bundles into a single file just the few "vendor" library files that your application actually needs.
The browser downloads this bundle, not the original package files.
See the [Deployment](guide/deployment) to learn more.

View File

@ -16,7 +16,7 @@ A good example of usage can be found on the [EventEmitter](https://angular.io/ap
Here is the component definition: Here is the component definition:
<code-example path="observables-in-angular/src/main.ts" title="EventEmitter" region="eventemitter"></code-example> <code-example path="observables-in-angular/src/main.ts" header="EventEmitter" region="eventemitter"></code-example>
## HTTP ## HTTP
Angulars `HttpClient` returns observables from HTTP method calls. For instance, `http.get(/api)` returns an observable. This provides several advantages over promise-based HTTP APIs: Angulars `HttpClient` returns observables from HTTP method calls. For instance, `http.get(/api)` returns an observable. This provides several advantages over promise-based HTTP APIs:
@ -32,20 +32,20 @@ The [AsyncPipe](https://angular.io/api/common/AsyncPipe) subscribes to an observ
The following example binds the `time` observable to the component's view. The observable continuously updates the view with the current time. The following example binds the `time` observable to the component's view. The observable continuously updates the view with the current time.
<code-example path="observables-in-angular/src/main.ts" title="Using async pipe" region="pipe"></code-example> <code-example path="observables-in-angular/src/main.ts" header="Using async pipe" region="pipe"></code-example>
## Router ## Router
[`Router.events`](https://angular.io/api/router/Router#events) provides events as observables. You can use the `filter()` operator from RxJS to look for events of interest, and subscribe to them in order to make decisions based on the sequence of events in the navigation process. Here's an example: [`Router.events`](https://angular.io/api/router/Router#events) provides events as observables. You can use the `filter()` operator from RxJS to look for events of interest, and subscribe to them in order to make decisions based on the sequence of events in the navigation process. Here's an example:
<code-example path="observables-in-angular/src/main.ts" title="Router events" region="router"></code-example> <code-example path="observables-in-angular/src/main.ts" header="Router events" region="router"></code-example>
The [ActivatedRoute](https://angular.io/api/router/ActivatedRoute) is an injected router service that makes use of observables to get information about a route path and parameters. For example, `ActivateRoute.url` contains an observable that reports the route path or paths. Here's an example: The [ActivatedRoute](https://angular.io/api/router/ActivatedRoute) is an injected router service that makes use of observables to get information about a route path and parameters. For example, `ActivateRoute.url` contains an observable that reports the route path or paths. Here's an example:
<code-example path="observables-in-angular/src/main.ts" title="ActivatedRoute" region="activated_route"></code-example> <code-example path="observables-in-angular/src/main.ts" header="ActivatedRoute" region="activated_route"></code-example>
## Reactive forms ## Reactive forms
Reactive forms have properties that use observables to monitor form control values. The [`FormControl`](https://angular.io/api/forms/FormControl) properties `valueChanges` and `statusChanges` contain observables that raise change events. Subscribing to an observable form-control property is a way of triggering application logic within the component class. For example: Reactive forms have properties that use observables to monitor form control values. The [`FormControl`](https://angular.io/api/forms/FormControl) properties `valueChanges` and `statusChanges` contain observables that raise change events. Subscribing to an observable form-control property is a way of triggering application logic within the component class. For example:
<code-example path="observables-in-angular/src/main.ts" title="Reactive forms" region="forms"></code-example> <code-example path="observables-in-angular/src/main.ts" header="Reactive forms" region="forms"></code-example>

View File

@ -1,3 +1,4 @@
# Observables # Observables
Observables provide support for passing messages between publishers and subscribers in your application. Observables offer significant benefits over other techniques for event handling, asynchronous programming, and handling multiple values. Observables provide support for passing messages between publishers and subscribers in your application. Observables offer significant benefits over other techniques for event handling, asynchronous programming, and handling multiple values.
@ -16,7 +17,7 @@ To execute the observable you have created and begin receiving notifications, yo
Here's an example that demonstrates the basic usage model by showing how an observable could be used to provide geolocation updates. Here's an example that demonstrates the basic usage model by showing how an observable could be used to provide geolocation updates.
<code-example path="observables/src/geolocation.ts" title="Observe geolocation updates"></code-example> <code-example path="observables/src/geolocation.ts" header="Observe geolocation updates"></code-example>
## Defining observers ## Defining observers
@ -36,10 +37,10 @@ An `Observable` instance begins publishing values only when someone subscribes t
<div class="alert is-helpful"> <div class="alert is-helpful">
In order to show how subscribing works, we need to create a new observable. There is a constructor that you use to create new instances, but for illustration, we can use some static methods on the `Observable` class that create simple observables of frequently used types: In order to show how subscribing works, we need to create a new observable. There is a constructor that you use to create new instances, but for illustration, we can use some methods from the RxJS library that create simple observables of frequently used types:
* `Observable.of(...items)`&mdash;Returns an `Observable` instance that synchronously delivers the values provided as arguments. * `of(...items)`&mdash;Returns an `Observable` instance that synchronously delivers the values provided as arguments.
* `Observable.from(iterable)`&mdash;Converts its argument to an `Observable` instance. This method is commonly used to convert an array to an observable. * `from(iterable)`&mdash;Converts its argument to an `Observable` instance. This method is commonly used to convert an array to an observable.
</div> </div>
@ -48,11 +49,11 @@ Here's an example of creating and subscribing to a simple observable, with an ob
<code-example <code-example
path="observables/src/subscribing.ts" path="observables/src/subscribing.ts"
region="observer" region="observer"
title="Subscribe using observer"></code-example> header="Subscribe using observer"></code-example>
Alternatively, the `subscribe()` method can accept callback function definitions in line, for `next`, `error`, and `complete` handlers. For example, the following `subscribe()` call is the same as the one that specifies the predefined observer: Alternatively, the `subscribe()` method can accept callback function definitions in line, for `next`, `error`, and `complete` handlers. For example, the following `subscribe()` call is the same as the one that specifies the predefined observer:
<code-example path="observables/src/subscribing.ts" region="sub_fn" title="Subscribe with positional arguments"></code-example> <code-example path="observables/src/subscribing.ts" region="sub_fn" header="Subscribe with positional arguments"></code-example>
In either case, a `next` handler is required. The `error` and `complete` handlers are optional. In either case, a `next` handler is required. The `error` and `complete` handlers are optional.
@ -62,17 +63,17 @@ Note that a `next()` function could receive, for instance, message strings, or e
Use the `Observable` constructor to create an observable stream of any type. The constructor takes as its argument the subscriber function to run when the observables `subscribe()` method executes. A subscriber function receives an `Observer` object, and can publish values to the observer's `next()` method. Use the `Observable` constructor to create an observable stream of any type. The constructor takes as its argument the subscriber function to run when the observables `subscribe()` method executes. A subscriber function receives an `Observer` object, and can publish values to the observer's `next()` method.
For example, to create an observable equivalent to the `Observable.of(1, 2, 3)` above, you could do something like this: For example, to create an observable equivalent to the `of(1, 2, 3)` above, you could do something like this:
<code-example path="observables/src/creating.ts" region="subscriber" title="Create observable with constructor"></code-example> <code-example path="observables/src/creating.ts" region="subscriber" header="Create observable with constructor"></code-example>
To take this example a little further, we can create an observable that publishes events. In this example, the subscriber function is defined inline. To take this example a little further, we can create an observable that publishes events. In this example, the subscriber function is defined inline.
<code-example path="observables/src/creating.ts" region="fromevent" title="Create with custom fromEvent function"></code-example> <code-example path="observables/src/creating.ts" region="fromevent" header="Create with custom fromEvent function"></code-example>
Now you can use this function to create an observable that publishes keydown events: Now you can use this function to create an observable that publishes keydown events:
<code-example path="observables/src/creating.ts" region="fromevent_use" title="Use custom fromEvent function"></code-example> <code-example path="observables/src/creating.ts" region="fromevent_use" header="Use custom fromEvent function"></code-example>
## Multicasting ## Multicasting
@ -86,15 +87,15 @@ When creating an observable you should determine how you want that observable to
Lets look at an example that counts from 1 to 3, with a one-second delay after each number emitted. Lets look at an example that counts from 1 to 3, with a one-second delay after each number emitted.
<code-example path="observables/src/multicasting.ts" region="delay_sequence" title="Create a delayed sequence"></code-example> <code-example path="observables/src/multicasting.ts" region="delay_sequence" header="Create a delayed sequence"></code-example>
Notice that if you subscribe twice, there will be two separate streams, each emitting values every second. It looks something like this: Notice that if you subscribe twice, there will be two separate streams, each emitting values every second. It looks something like this:
<code-example path="observables/src/multicasting.ts" region="subscribe_twice" title="Two subscriptions"></code-example> <code-example path="observables/src/multicasting.ts" region="subscribe_twice" header="Two subscriptions"></code-example>
Changing the observable to be multicasting could look something like this: Changing the observable to be multicasting could look something like this:
<code-example path="observables/src/multicasting.ts" region="multicast_sequence" title="Create a multicast subscriber"></code-example> <code-example path="observables/src/multicasting.ts" region="multicast_sequence" header="Create a multicast subscriber"></code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
Multicasting observables take a bit more setup, but they can be useful for certain applications. Later we will look at tools that simplify the process of multicasting, allowing you to take any observable and make it multicasting. Multicasting observables take a bit more setup, but they can be useful for certain applications. Later we will look at tools that simplify the process of multicasting, allowing you to take any observable and make it multicasting.

View File

@ -26,7 +26,7 @@ In this page, you'll use pipes to transform a component's birthday property into
a human-friendly date. a human-friendly date.
<code-example path="pipes/src/app/hero-birthday1.component.ts" title="src/app/hero-birthday1.component.ts" linenums="false"> <code-example path="pipes/src/app/hero-birthday1.component.ts" header="src/app/hero-birthday1.component.ts" linenums="false">
</code-example> </code-example>
@ -35,7 +35,7 @@ a human-friendly date.
Focus on the component's template. Focus on the component's template.
<code-example path="pipes/src/app/app.component.html" region="hero-birthday-template" title="src/app/app.component.html" linenums="false"> <code-example path="pipes/src/app/app.component.html" region="hero-birthday-template" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -79,7 +79,7 @@ Modify the birthday template to give the date pipe a format parameter.
After formatting the hero's April 15th birthday, it renders as **<samp>04/15/88</samp>**: After formatting the hero's April 15th birthday, it renders as **<samp>04/15/88</samp>**:
<code-example path="pipes/src/app/app.component.html" region="format-birthday" title="src/app/app.component.html" linenums="false"> <code-example path="pipes/src/app/app.component.html" region="format-birthday" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -95,7 +95,7 @@ Write a second component that *binds* the pipe's format parameter
to the component's `format` property. Here's the template for that component: to the component's `format` property. Here's the template for that component:
<code-example path="pipes/src/app/hero-birthday2.component.ts" region="template" title="src/app/hero-birthday2.component.ts (template)" linenums="false"> <code-example path="pipes/src/app/hero-birthday2.component.ts" region="template" header="src/app/hero-birthday2.component.ts (template)" linenums="false">
</code-example> </code-example>
@ -106,7 +106,7 @@ That method toggles the component's `format` property between a short form
(`'shortDate'`) and a longer form (`'fullDate'`). (`'shortDate'`) and a longer form (`'fullDate'`).
<code-example path="pipes/src/app/hero-birthday2.component.ts" region="class" title="src/app/hero-birthday2.component.ts (class)" linenums="false"> <code-example path="pipes/src/app/hero-birthday2.component.ts" region="class" header="src/app/hero-birthday2.component.ts (class)" linenums="false">
</code-example> </code-example>
@ -143,7 +143,7 @@ the birthday is chained to the `DatePipe` and on to the `UpperCasePipe`.
The birthday displays as **<samp>APR 15, 1988</samp>**. The birthday displays as **<samp>APR 15, 1988</samp>**.
<code-example path="pipes/src/app/app.component.html" region="chained-birthday" title="src/app/app.component.html" linenums="false"> <code-example path="pipes/src/app/app.component.html" region="chained-birthday" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -153,7 +153,7 @@ This example&mdash;which displays **<samp>FRIDAY, APRIL 15, 1988</samp>**&mdash;
the same pipes as above, but passes in a parameter to `date` as well. the same pipes as above, but passes in a parameter to `date` as well.
<code-example path="pipes/src/app/app.component.html" region="chained-parameter-birthday" title="src/app/app.component.html" linenums="false"> <code-example path="pipes/src/app/app.component.html" region="chained-parameter-birthday" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -166,7 +166,7 @@ You can write your own custom pipes.
Here's a custom pipe named `ExponentialStrengthPipe` that can boost a hero's powers: Here's a custom pipe named `ExponentialStrengthPipe` that can boost a hero's powers:
<code-example path="pipes/src/app/exponential-strength.pipe.ts" title="src/app/exponential-strength.pipe.ts" linenums="false"> <code-example path="pipes/src/app/exponential-strength.pipe.ts" header="src/app/exponential-strength.pipe.ts" linenums="false">
</code-example> </code-example>
@ -200,7 +200,7 @@ Technically, it's optional; Angular looks for and executes the `transform` metho
Now you need a component to demonstrate the pipe. Now you need a component to demonstrate the pipe.
<code-example path="pipes/src/app/power-booster.component.ts" title="src/app/power-booster.component.ts" linenums="false"> <code-example path="pipes/src/app/power-booster.component.ts" header="src/app/power-booster.component.ts" linenums="false">
</code-example> </code-example>
<figure> <figure>
@ -223,7 +223,7 @@ Note the following:
You must register custom pipes. You must register custom pipes.
If you don't, Angular reports an error. If you don't, Angular reports an error.
Angular CLI's generator registers the pipe automatically. The [Angular CLI's](cli) generator registers the pipe automatically.
</div> </div>
@ -240,7 +240,7 @@ Upgrade the example to a "Power Boost Calculator" that combines
your pipe and two-way data binding with `ngModel`. your pipe and two-way data binding with `ngModel`.
<code-example path="pipes/src/app/power-boost-calculator.component.ts" title="src/app/power-boost-calculator.component.ts"> <code-example path="pipes/src/app/power-boost-calculator.component.ts" header="src/app/power-boost-calculator.component.ts">
</code-example> </code-example>
@ -270,7 +270,7 @@ In the next example, the component uses the default, aggressive change detection
its display of every hero in the `heroes` array. Here's the template: its display of every hero in the `heroes` array. Here's the template:
<code-example path="pipes/src/app/flying-heroes.component.html" region="template-1" title="src/app/flying-heroes.component.html (v1)" linenums="false"> <code-example path="pipes/src/app/flying-heroes.component.html" region="template-1" header="src/app/flying-heroes.component.html (v1)" linenums="false">
</code-example> </code-example>
@ -278,7 +278,7 @@ its display of every hero in the `heroes` array. Here's the template:
The companion component class provides heroes, adds heroes into the array, and can reset the array. The companion component class provides heroes, adds heroes into the array, and can reset the array.
<code-example path="pipes/src/app/flying-heroes.component.ts" region="v1" title="src/app/flying-heroes.component.ts (v1)" linenums="false"> <code-example path="pipes/src/app/flying-heroes.component.ts" region="v1" header="src/app/flying-heroes.component.ts (v1)" linenums="false">
</code-example> </code-example>
@ -292,7 +292,7 @@ If you added the ability to remove or change a hero, Angular would detect those
Add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroes to just those heroes who can fly. Add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroes to just those heroes who can fly.
<code-example path="pipes/src/app/flying-heroes.component.html" region="template-flying-heroes" title="src/app/flying-heroes.component.html (flyers)" linenums="false"> <code-example path="pipes/src/app/flying-heroes.component.html" region="template-flying-heroes" header="src/app/flying-heroes.component.html (flyers)" linenums="false">
</code-example> </code-example>
@ -300,7 +300,7 @@ Add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroe
Here's the `FlyingHeroesPipe` implementation, which follows the pattern for custom pipes described earlier. Here's the `FlyingHeroesPipe` implementation, which follows the pattern for custom pipes described earlier.
<code-example path="pipes/src/app/flying-heroes.pipe.ts" region="pure" title="src/app/flying-heroes.pipe.ts" linenums="false"> <code-example path="pipes/src/app/flying-heroes.pipe.ts" region="pure" header="src/app/flying-heroes.pipe.ts" linenums="false">
</code-example> </code-example>
@ -314,7 +314,7 @@ It's just using a different change-detection algorithm that ignores changes to t
Notice how a hero is added: Notice how a hero is added:
<code-example path="pipes/src/app/flying-heroes.component.ts" region="push" title="src/app/flying-heroes.component.ts" linenums="false"> <code-example path="pipes/src/app/flying-heroes.component.ts" region="push" header="src/app/flying-heroes.component.ts" linenums="false">
</code-example> </code-example>
@ -364,7 +364,7 @@ You make a pipe impure by setting its pure flag to false. You could make the `Fl
impure like this: impure like this:
<code-example path="pipes/src/app/flying-heroes.pipe.ts" region="pipe-decorator" title="src/app/flying-heroes.pipe.ts" linenums="false"> <code-example path="pipes/src/app/flying-heroes.pipe.ts" region="pipe-decorator" header="src/app/flying-heroes.pipe.ts" linenums="false">
</code-example> </code-example>
@ -422,11 +422,11 @@ The complete implementation is as follows:
<code-tabs> <code-tabs>
<code-pane title="FlyingHeroesImpurePipe" path="pipes/src/app/flying-heroes.pipe.ts" region="impure"> <code-pane header="FlyingHeroesImpurePipe" path="pipes/src/app/flying-heroes.pipe.ts" region="impure">
</code-pane> </code-pane>
<code-pane title="FlyingHeroesPipe" path="pipes/src/app/flying-heroes.pipe.ts" region="pure"> <code-pane header="FlyingHeroesPipe" path="pipes/src/app/flying-heroes.pipe.ts" region="pure">
</code-pane> </code-pane>
@ -440,7 +440,7 @@ The only difference is the `pure` flag in the pipe metadata.
This is a good candidate for an impure pipe because the `transform` function is trivial and fast. This is a good candidate for an impure pipe because the `transform` function is trivial and fast.
<code-example path="pipes/src/app/flying-heroes.pipe.ts" linenums="false" title="src/app/flying-heroes.pipe.ts (filter)" region="filter"> <code-example path="pipes/src/app/flying-heroes.pipe.ts" linenums="false" header="src/app/flying-heroes.pipe.ts (filter)" region="filter">
</code-example> </code-example>
@ -449,7 +449,7 @@ This is a good candidate for an impure pipe because the `transform` function is
You can derive a `FlyingHeroesImpureComponent` from `FlyingHeroesComponent`. You can derive a `FlyingHeroesImpureComponent` from `FlyingHeroesComponent`.
<code-example path="pipes/src/app/flying-heroes-impure.component.html" linenums="false" title="src/app/flying-heroes-impure.component.html (excerpt)" region="template-flying-heroes"> <code-example path="pipes/src/app/flying-heroes-impure.component.html" linenums="false" header="src/app/flying-heroes-impure.component.html (excerpt)" region="template-flying-heroes">
</code-example> </code-example>
@ -476,7 +476,7 @@ This next example binds an `Observable` of message strings
(`message$`) to a view with the `async` pipe. (`message$`) to a view with the `async` pipe.
<code-example path="pipes/src/app/hero-async-message.component.ts" title="src/app/hero-async-message.component.ts"> <code-example path="pipes/src/app/hero-async-message.component.ts" header="src/app/hero-async-message.component.ts">
</code-example> </code-example>
@ -499,7 +499,7 @@ In the following code, the pipe only calls the server when the request URL chang
The code uses the [Angular http](guide/http) client to retrieve data: The code uses the [Angular http](guide/http) client to retrieve data:
<code-example path="pipes/src/app/fetch-json.pipe.ts" title="src/app/fetch-json.pipe.ts"> <code-example path="pipes/src/app/fetch-json.pipe.ts" header="src/app/fetch-json.pipe.ts">
</code-example> </code-example>
@ -509,7 +509,7 @@ Now demonstrate it in a harness component whose template defines two bindings to
both requesting the heroes from the `heroes.json` file. both requesting the heroes from the `heroes.json` file.
<code-example path="pipes/src/app/hero-list.component.ts" title="src/app/hero-list.component.ts"> <code-example path="pipes/src/app/hero-list.component.ts" header="src/app/hero-list.component.ts">
</code-example> </code-example>

View File

@ -14,10 +14,10 @@ Observables can simplify the implementation of type-ahead suggestions. Typically
Writing this in full JavaScript can be quite involved. With observables, you can use a simple series of RxJS operators: Writing this in full JavaScript can be quite involved. With observables, you can use a simple series of RxJS operators:
<code-example path="practical-observable-usage/src/typeahead.ts" title="Typeahead"></code-example> <code-example path="practical-observable-usage/src/typeahead.ts" header="Typeahead"></code-example>
## Exponential backoff ## Exponential backoff
Exponential backoff is a technique in which you retry an API after failure, making the time in between retries longer after each consecutive failure, with a maximum number of retries after which the request is considered to have failed. This can be quite complex to implement with promises and other methods of tracking AJAX calls. With observables, it is very easy: Exponential backoff is a technique in which you retry an API after failure, making the time in between retries longer after each consecutive failure, with a maximum number of retries after which the request is considered to have failed. This can be quite complex to implement with promises and other methods of tracking AJAX calls. With observables, it is very easy:
<code-example path="practical-observable-usage/src/backoff.ts" title="Exponential backoff"></code-example> <code-example path="practical-observable-usage/src/backoff.ts" header="Exponential backoff"></code-example>

View File

@ -13,7 +13,7 @@ A provider is an instruction to the DI system on how to obtain a value for a dep
## Providing a service ## Providing a service
If you already have a CLI generated app, create a service using the following CLI command in the root project directory. Replace _User_ with the name of your service. If you already have an app that was created with the [Angular CLI](cli), you can create a service using the [`ng generate`](cli/generate) CLI command in the root project directory. Replace _User_ with the name of your service.
```sh ```sh
ng generate service User ng generate service User
@ -21,7 +21,7 @@ ng generate service User
This command creates the following `UserService` skeleton: This command creates the following `UserService` skeleton:
<code-example path="providers/src/app/user.service.0.ts" title="src/app/user.service.0.ts" linenums="false"> </code-example> <code-example path="providers/src/app/user.service.0.ts" header="src/app/user.service.0.ts" linenums="false"> </code-example>
You can now inject `UserService` anywhere in your application. You can now inject `UserService` anywhere in your application.
@ -38,15 +38,15 @@ You should always provide your service in the root injector unless there is a ca
It's also possible to specify that a service should be provided in a particular `@NgModule`. For example, if you don't want `UserService` to be available to applications unless they import a `UserModule` you've created, you can specify that the service should be provided in the module: It's also possible to specify that a service should be provided in a particular `@NgModule`. For example, if you don't want `UserService` to be available to applications unless they import a `UserModule` you've created, you can specify that the service should be provided in the module:
<code-example path="providers/src/app/user.service.1.ts" title="src/app/user.service.1.ts" linenums="false"> </code-example> <code-example path="providers/src/app/user.service.1.ts" header="src/app/user.service.1.ts" linenums="false"> </code-example>
The example above shows the preferred way to provide a service in a module. This method is preferred because it enables tree-shaking of the service if nothing injects it. If it's not possible to specify in the service which module should provide it, you can also declare a provider for the service within the module: The example above shows the preferred way to provide a service in a module. This method is preferred because it enables tree-shaking of the service if nothing injects it. If it's not possible to specify in the service which module should provide it, you can also declare a provider for the service within the module:
<code-example path="providers/src/app/user.module.ts" title="src/app/user.module.ts" linenums="false"> </code-example> <code-example path="providers/src/app/user.module.ts" header="src/app/user.module.ts" linenums="false"> </code-example>
## Limiting provider scope by lazy loading modules ## Limiting provider scope by lazy loading modules
In the basic CLI generated app, modules are eagerly loaded which means that they are all loaded when the app launches. Angular uses an injector system to make things available between modules. In an eagerly loaded app, the root application injector makes all of the providers in all of the modules available throughout the app. In the basic CLI-generated app, modules are eagerly loaded which means that they are all loaded when the app launches. Angular uses an injector system to make things available between modules. In an eagerly loaded app, the root application injector makes all of the providers in all of the modules available throughout the app.
This behavior necessarily changes when you use lazy loading. Lazy loading is when you load modules only when you need them; for example, when routing. They arent loaded right away like with eagerly loaded modules. This means that any services listed in their provider arrays arent available because the root injector doesnt know about these modules. This behavior necessarily changes when you use lazy loading. Lazy loading is when you load modules only when you need them; for example, when routing. They arent loaded right away like with eagerly loaded modules. This means that any services listed in their provider arrays arent available because the root injector doesnt know about these modules.
@ -67,7 +67,7 @@ method is helpful for when you want to eagerly load a module that needs a servic
Providing a service in the component limits the service only to that component (other components in Providing a service in the component limits the service only to that component (other components in
the same module cant access it.) the same module cant access it.)
<code-example path="providers/src/app/app.component.ts" region="component-providers" title="src/app/app.component.ts" linenums="false"> <code-example path="providers/src/app/app.component.ts" region="component-providers" header="src/app/app.component.ts" linenums="false">
</code-example> </code-example>

View File

@ -1,46 +1,51 @@
# QuickStart # Getting started
Good tools make application development quicker and easier to maintain than Welcome to Angular! Angular helps you build modern applications for the web, mobile, or desktop.
if you did everything by hand.
The [**Angular CLI**](https://cli.angular.io/) is a **_command line interface_** tool This guide shows you how to build and run a simple Angular
that can create a project, add files, and perform a variety of ongoing development tasks such app. You'll use the [Angular CLI tool](cli "CLI command reference") to accelerate development,
as testing, bundling, and deployment. while adhering to the [Style Guide](guide/styleguide "Angular style guide") recommendations that
The goal in this guide is to build and run a simple Angular
application in TypeScript, using the Angular CLI
while adhering to the [Style Guide](guide/styleguide) recommendations that
benefit _every_ Angular project. benefit _every_ Angular project.
By the end of the chapter, you'll have a basic understanding of development with the CLI This guide takes less than 30 minutes to complete.
and a foundation for both these documentation samples and for real world applications. At the end of this guide&mdash;as part of final code review&mdash;there is a link to download a copy of the final application code. (If you don't execute the commands in this guide, you can still download the final application code.)
And you can also <a href="generated/zips/cli-quickstart/cli-quickstart.zip" target="_blank">download the example.</a>
<h2 id='devenv'>
Step 1. Set up the Development Environment
</h2>
{@a devenv}
{@a prerequisites}
## Prerequisites
You need to set up your development environment before you can do anything. Before you begin, make sure your development environment includes `Node.js®` and an npm package manager.
Install **[Node.js® and npm](https://nodejs.org/en/download/)** {@a nodejs}
if they are not already on your machine. ### Node.js
<div class="alert is-helpful"> Angular requires `Node.js` version 8.x or 10.x.
* To check your version, run `node -v` in a terminal/console window.
* To get `Node.js`, go to [nodejs.org](https://nodejs.org "Nodejs.org").
{@a npm}
### npm package manager
Angular, the Angular CLI, and Angular apps depend on features and functionality provided by libraries that are available as [npm packages](https://docs.npmjs.com/getting-started/what-is-npm). To download and install npm packages, you must have an npm package manager.
This Quick Start uses the [npm client](https://docs.npmjs.com/cli/install) command line interface, which is installed with `Node.js` by default.
To check that you have the npm client installed, run `npm -v` in a terminal/console window.
{@a install-cli}
**Verify that you are running at least Node.js version `8.x` or greater and npm version `5.x` or greater** ## Step 1: Install the Angular CLI
by running `node -v` and `npm -v` in a terminal/console window.
Older versions produce errors, but newer versions are fine.
</div> You use the Angular CLI
to create projects, generate application and library code, and perform a variety of ongoing development tasks such as testing, bundling, and deployment.
Install the Angular CLI globally.
To install the CLI using `npm`, open a terminal/console window and enter the following command:
Then install the [Angular CLI](https://github.com/angular/angular-cli) globally.
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
@ -50,592 +55,130 @@ Then install the [Angular CLI](https://github.com/angular/angular-cli) globally.
{@a create-proj}
<h2 id='create-proj'> ## Step 2: Create a workspace and initial application
Step 2. Create a new project
</h2>
You develop apps in the context of an Angular [**workspace**](guide/glossary#workspace). A workspace contains the files for one or more [**projects**](guide/glossary/#project). A project is the set of files that comprise an app, a library, or end-to-end (e2e) tests.
To create a new workspace and initial app project:
Open a terminal window. 1. Run the CLI command `ng new` and provide the name `my-app`, as shown here:
<code-example language="sh" class="code-shell">
ng new my-app
Generate a new project and default app by running the following command: </code-example>
2. The `ng new` command prompts you for information about features to include in the initial app project. Accept the defaults by pressing the Enter or Return key.
<code-example language="sh" class="code-shell"> The Angular CLI installs the necessary Angular npm packages and other dependencies. This can take a few minutes.
ng new my-app
</code-example> It also creates the following workspace and starter project files:
* A new workspace, with a root folder named `my-app`
* An initial skeleton app project, also called `my-app` (in the `src` subfolder)
* An end-to-end test project (in the `e2e` subfolder)
* Related configuration files
The Angular CLI installs the necessary npm packages, creates the project files, and populates the project with a simple default app. This can take some time. The initial app project contains a simple Welcome app, ready to run.
{@a serve}
## Step 3: Serve the application
<div class="alert is-helpful"> Angular includes a server, so that you can easily build and serve your app locally.
1. Go to the workspace folder (`my-app`).
1. Launch the server by using the CLI command `ng serve`, with the `--open` option.
You can add pre-packaged functionality to a new project by using the `ng add` command. The `ng add` command transforms a project by applying the schematics in the specified package.
For more information, see the [Angular CLI documentation.](https://github.com/angular/angular-cli/wiki/add "Angular CLI documentation")
Angular Material provides schematics for typical app layouts.
See the [Angular Material documentation](https://material.angular.io/guides "Angular Material documentation") for details.
</div>
<h2 id='serve'>
Step 3: Serve the application
</h2>
Go to the project directory and launch the server.
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
cd my-app cd my-app
ng serve --open ng serve --open
</code-example> </code-example>
The `ng serve` command launches the server, watches your files, The `ng serve` command launches the server, watches your files,
and rebuilds the app as you make changes to those files. and rebuilds the app as you make changes to those files.
Using the `--open` (or just `-o`) option will automatically open your browser The `--open` (or just `-o`) option automatically opens your browser
on `http://localhost:4200/`. to `http://localhost:4200/`.
Your app greets you with a message: Your app greets you with a message:
<figure> <figure>
<img src='generated/images/guide/cli-quickstart/app-works.png' alt="The app works!"> <img src='generated/images/guide/cli-quickstart/app-works.png' alt="Welcome to my-app!">
</figure> </figure>
{@a first-component}
<h2 id='first-component'> ## Step 4: Edit your first Angular component
Step 4: Edit your first Angular component
</h2>
[**_Components_**](guide/glossary#component) are the fundamental building blocks of Angular applications.
They display data on the screen, listen for user input, and take action based on that input.
As part of the initial app, the CLI created the first Angular component for you. It is the _root component_, and it is named `app-root`.
The CLI created the first Angular component for you. 1. Open `./src/app/app.component.ts`.
This is the _root component_ and it is named `app-root`.
You can find it in `./src/app/app.component.ts`.
2. Change the `title` property from `'my-app'` to `'My First Angular App'`.
Open the component file and change the `title` property from `'app'` to `'My First Angular App!'`. <code-example path="cli-quickstart/src/app/app.component.ts" region="component" header="src/app/app.component.ts" linenums="false"></code-example>
The browser reloads automatically with the revised title. That's nice, but it could look better.
<code-example path="cli-quickstart/src/app/app.component.ts" region="title" title="src/app/app.component.ts" linenums="false"></code-example> 3. Open `./src/app/app.component.css` and give the component some style.
The browser reloads automatically with the revised title. That's nice, but it could look better.
Open `src/app/app.component.css` and give the component some style.
<code-example path="cli-quickstart/src/app/app.component.css" title="src/app/app.component.css" linenums="false"></code-example>
<code-example path="cli-quickstart/src/app/app.component.css" header="src/app/app.component.css" linenums="false"></code-example>
Looking good!
<figure> <figure>
<img src='generated/images/guide/cli-quickstart/my-first-app.png' alt="Output of QuickStart app"> <img src='generated/images/guide/cli-quickstart/my-first-app.png' alt="Output of Getting Started app">
</figure> </figure>
Looking good!
{@a project-file-review}
## Final code review
## What's next? You can <a href="generated/zips/cli-quickstart/cli-quickstart.zip" target="_blank">download an example</a> of the app that you created in this Getting Started guide.
That's about all you'd expect to do in a "Hello, World" app.
You're ready to take the [Tour of Heroes Tutorial](tutorial) and build
a small application that demonstrates the great things you can build with Angular.
Or you can stick around a bit longer to learn about the files in your brand new project.
## Project file review
An Angular CLI project is the foundation for both quick experiments and enterprise solutions.
The first file you should check out is `README.md`.
It has some basic information on how to use CLI commands.
Whenever you want to know more about how Angular CLI works make sure to visit
[the Angular CLI repository](https://github.com/angular/angular-cli) and
[Wiki](https://github.com/angular/angular-cli/wiki).
Some of the generated files might be unfamiliar to you.
### The `src` folder
Your app lives in the `src` folder.
All Angular components, templates, styles, images, and anything else your app needs go here.
Any files outside of this folder are meant to support building your app.
<div class='filetree'>
<div class='file'>src</div>
<div class='children'>
<div class='file'>app</div>
<div class='children'>
<div class='file'>app.component.css</div>
<div class='file'>app.component.html</div>
<div class="file">app.component.spec.ts</div>
<div class="file">app.component.ts</div>
<div class="file">app.module.ts</div>
</div>
<div class="file">assets</div>
<div class='children'>
<div class="file">.gitkeep</div>
</div>
<div class="file">environments</div>
<div class='children'>
<div class="file">environment.prod.ts</div>
<div class="file">environment.ts</div>
</div>
<div class="file">browserslist</div>
<div class="file">favicon.ico</div>
<div class="file">index.html</div>
<div class="file">karma.conf.js</div>
<div class="file">main.ts</div>
<div class="file">polyfills.ts</div>
<div class="file">styles.css</div>
<div class="file">test.ts</div>
<div class="file">tsconfig.app.json</div>
<div class="file">tsconfig.spec.json</div>
<div class="file">tslint.json</div>
</div>
</div>
<style>
td, th {vertical-align: top}
</style>
<table width="100%">
<col width="20%">
</col>
<col width="80%">
</col>
<tr>
<th>
File
</th>
<th>
Purpose
</th>
</tr>
<tr>
<td>
`app/app.component.{ts,html,css,spec.ts}`
</td>
<td>
Defines the `AppComponent` along with an HTML template, CSS stylesheet, and a unit test.
It is the **root** component of what will become a tree of nested components
as the application evolves.
</td>
</tr>
<tr>
<td>
`app/app.module.ts`
</td>
<td>
Defines `AppModule`, the [root module](guide/bootstrapping "AppModule: the root module") that tells Angular how to assemble the application.
Right now it declares only the `AppComponent`.
Soon there will be more components to declare.
</td>
</tr>
<tr>
<td>
`assets/*`
</td>
<td>
A folder where you can put images and anything else to be copied wholesale
when you build your application.
</td>
</tr>
<tr>
<td>
`environments/*`
</td>
<td>
This folder contains one file for each of your destination environments,
each exporting simple configuration variables to use in your application.
The files are replaced on-the-fly when you build your app.
You might use a different API endpoint for development than you do for production
or maybe different analytics tokens.
You might even use some mock services.
Either way, the CLI has you covered.
</td>
</tr>
<tr>
<td>
`browserslist`
</td>
<td>
A configuration file to share [target browsers](https://github.com/browserslist/browserslist) between different front-end tools.
</td>
</tr>
<tr>
<td>
`favicon.ico`
</td>
<td>
Every site wants to look good on the bookmark bar.
Get started with your very own Angular icon.
</td>
</tr>
<tr>
<td>
`index.html`
</td>
<td>
The main HTML page that is served when someone visits your site.
Most of the time you'll never need to edit it.
The CLI automatically adds all `js` and `css` files when building your app so you
never need to add any `<script>` or `<link>` tags here manually.
</td>
</tr>
<tr>
<td>
`karma.conf.js`
</td>
<td>
Unit test configuration for the [Karma test runner](https://karma-runner.github.io),
used when running `ng test`.
</td>
</tr>
<tr>
<td>
`main.ts`
</td>
<td>
The main entry point for your app.
Compiles the application with the [JIT compiler](guide/glossary#jit)
and bootstraps the application's root module (`AppModule`) to run in the browser.
You can also use the [AOT compiler](guide/aot-compiler)
without changing any code by appending the`--aot` flag to the `ng build` and `ng serve` commands.
</td>
</tr>
<tr>
<td>
`polyfills.ts`
</td>
<td>
Different browsers have different levels of support of the web standards.
Polyfills help normalize those differences.
You should be pretty safe with `core-js` and `zone.js`, but be sure to check out
the [Browser Support guide](guide/browser-support) for more information.
</td>
</tr>
<tr>
<td>
`styles.css`
</td>
<td>
Your global styles go here.
Most of the time you'll want to have local styles in your components for easier maintenance,
but styles that affect all of your app need to be in a central place.
</td>
</tr>
<tr>
<td>
`test.ts`
</td>
<td>
This is the main entry point for your unit tests.
It has some custom configuration that might be unfamiliar, but it's not something you'll
need to edit.
</td>
</tr>
<tr>
<td>
`tsconfig.{app|spec}.json`
</td>
<td>
TypeScript compiler configuration for the Angular app (`tsconfig.app.json`)
and for the unit tests (`tsconfig.spec.json`).
</td>
</tr>
<tr>
<td>
`tslint.json`
</td>
<td>
Additional Linting configuration for [TSLint](https://palantir.github.io/tslint/) together with
[Codelyzer](http://codelyzer.com/), used when running `ng lint`.
Linting helps keep your code style consistent.
</td>
</tr>
</table>
### The root folder
The `src/` folder is just one of the items inside the project's root folder.
Other files help you build, test, maintain, document, and deploy the app.
These files go in the root folder next to `src/`.
<div class='filetree'>
<div class="file">my-app</div>
<div class='children'>
<div class="file">e2e</div>
<div class='children'>
<div class="file">src</div>
<div class='children'>
<div class="file">app.e2e-spec.ts</div>
<div class="file">app.po.ts</div>
</div>
<div class="file">tsconfig.e2e.json</div>
<div class="file">protractor.conf.js</div>
</div>
<div class="file">node_modules/...</div>
<div class="file">src/...</div>
<div class='children'>
<div class="file">karma.conf.js</div>
</div>
<div class="file">.editorconfig</div>
<div class="file">.gitignore</div>
<div class="file">angular.json</div>
<div class="file">package.json</div>
<div class="file">README.md</div>
<div class="file">tsconfig.json</div>
<div class="file">tslint.json</div>
</div>
</div>
<style>
td, th {vertical-align: top}
</style>
<table width="100%">
<col width="20%">
</col>
<col width="80%">
</col>
<tr>
<th>
File
</th>
<th>
Purpose
</th>
</tr>
<tr>
<td>
`e2e/`
</td>
<td>
Inside `e2e/` live the end-to-end tests.
They shouldn't be inside `src/` because e2e tests are really a separate app that
just so happens to test your main app.
That's also why they have their own `tsconfig.e2e.json`.
</td>
</tr>
<tr>
<td>
`node_modules/`
</td>
<td>
`Node.js` creates this folder and puts all third party modules listed in
`package.json` inside of it.
</td>
</tr>
<tr>
<td>
`.editorconfig`
</td>
<td>
Simple configuration for your editor to make sure everyone that uses your project
has the same basic configuration.
Most editors support an `.editorconfig` file.
See http://editorconfig.org for more information.
</td>
</tr>
<tr>
<td>
`.gitignore`
</td>
<td>
Git configuration to make sure autogenerated files are not committed to source control.
</td>
</tr>
<tr>
<td>
`angular.json`
</td>
<td>
Configuration for Angular CLI.
In this file you can set several defaults and also configure what files are included
when your project is built.
Check out the official documentation if you want to know more.
</td>
</tr>
<tr>
<td>
`package.json`
</td>
<td>
`npm` configuration listing the third party packages your project uses.
You can also add your own [custom scripts](https://docs.npmjs.com/misc/scripts) here.
</td>
</tr>
<tr>
<td>
`protractor.conf.js`
</td>
<td>
End-to-end test configuration for [Protractor](http://www.protractortest.org/),
used when running `ng e2e`.
</td>
</tr>
<tr>
<td>
`README.md`
</td>
<td>
Basic documentation for your project, pre-filled with CLI command information.
Make sure to enhance it with project documentation so that anyone
checking out the repo can build your app!
</td>
</tr>
<tr>
<td>
`tsconfig.json`
</td>
<td>
TypeScript compiler configuration for your IDE to pick up and give you helpful tooling.
</td>
</tr>
<tr>
<td>
`tslint.json`
</td>
<td>
Linting configuration for [TSLint](https://palantir.github.io/tslint/) together with
[Codelyzer](http://codelyzer.com/), used when running `ng lint`.
Linting helps keep your code style consistent.
</td>
</tr>
</table>
<div class="alert is-helpful"> <div class="alert is-helpful">
### Next Step **Tip:** Most Angular guides include links to download example files and run live examples in [Stackblitz](http://www.stackblitz.com), so that you can see Angular concepts and code in action.
If you're new to Angular, continue with the
[tutorial](tutorial "Tour of Heroes tutorial").
You can skip the "Setup" step since you're already using the Angular CLI setup.
</div> </div>
For more information about Angular project files and the file structure, see [Workspace and project file struture](guide/file-structure).
## Next steps
Now that you've seen the essentials of an Angular app and the Angular CLI, continue with these other introductory materials:
* The [Tour of Heroes tutorial](tutorial "Tour of Heroes tutorial") provides additional hands-on learning. It walks you through the steps to build an app that helps a staffing agency manage a group of superhero employees.
It has many of the features you'd expect to find in a data-driven application:
- Acquiring and displaying a list of items
- Editing a selected item's detail
- Navigating among different views of the data
* The [Architecture guide](guide/architecture "Architecture guide") describes key concepts such as modules, components, services, and dependency injection (DI). It provides a foundation for more in-depth guides about specific Angular concepts and features.
After the Tutorial and Architecture guide, you'll be ready to continue exploring Angular on your own through the other guides and references in this documentation set, focusing on the features most important for your apps.

View File

@ -26,7 +26,7 @@ This section describes how to add a single form control. In the example, the use
To use reactive forms, import `ReactiveFormsModule` from the `@angular/forms` package and add it to your NgModule's `imports` array. To use reactive forms, import `ReactiveFormsModule` from the `@angular/forms` package and add it to your NgModule's `imports` array.
<code-example path="reactive-forms/src/app/app.module.ts" region="imports" title="src/app/app.module.ts (excerpt)"> <code-example path="reactive-forms/src/app/app.module.ts" region="imports" header="src/app/app.module.ts (excerpt)">
</code-example> </code-example>
@ -42,7 +42,7 @@ Generate a component for the control.
The `FormControl` class is the basic building block when using reactive forms. To register a single form control, import the `FormControl` class into your component and create a new instance of the form control to save as a class property. The `FormControl` class is the basic building block when using reactive forms. To register a single form control, import the `FormControl` class into your component and create a new instance of the form control to save as a class property.
<code-example path="reactive-forms/src/app/name-editor/name-editor.component.ts" region="create-control" title="src/app/name-editor/name-editor.component.ts"> <code-example path="reactive-forms/src/app/name-editor/name-editor.component.ts" region="create-control" header="src/app/name-editor/name-editor.component.ts">
</code-example> </code-example>
@ -52,7 +52,7 @@ Use the constructor of `FormControl` to set its initial value, which in this cas
After you create the control in the component class, you must associate it with a form control element in the template. Update the template with the form control using the `formControl` binding provided by `FormControlDirective` included in `ReactiveFormsModule`. After you create the control in the component class, you must associate it with a form control element in the template. Update the template with the form control using the `formControl` binding provided by `FormControlDirective` included in `ReactiveFormsModule`.
<code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="control-binding" linenums="false" title="src/app/name-editor/name-editor.component.html"> <code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="control-binding" linenums="false" header="src/app/name-editor/name-editor.component.html">
</code-example> </code-example>
@ -68,7 +68,7 @@ Using the template binding syntax, the form control is now registered to the `na
The form control assigned to `name` is displayed when the component is added to a template. The form control assigned to `name` is displayed when the component is added to a template.
<code-example path="reactive-forms/src/app/app.component.1.html" region="app-name-editor" linenums="false" title="src/app/app.component.html (name editor)"> <code-example path="reactive-forms/src/app/app.component.1.html" region="app-name-editor" linenums="false" header="src/app/app.component.html (name editor)">
</code-example> </code-example>
@ -92,7 +92,7 @@ You can display the value in these ways:
The following example shows you how to display the current value using interpolation in the template. The following example shows you how to display the current value using interpolation in the template.
<code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="display-value" linenums="false" title="src/app/name-editor/name-editor.component.html (control value)"> <code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="display-value" linenums="false" header="src/app/name-editor/name-editor.component.html (control value)">
</code-example> </code-example>
@ -108,13 +108,13 @@ Reactive forms have methods to change a control's value programmatically, which
The following example adds a method to the component class to update the value of the control to *Nancy* using the `setValue()` method. The following example adds a method to the component class to update the value of the control to *Nancy* using the `setValue()` method.
<code-example path="reactive-forms/src/app/name-editor/name-editor.component.ts" region="update-value" title="src/app/name-editor/name-editor.component.ts (update value)"> <code-example path="reactive-forms/src/app/name-editor/name-editor.component.ts" region="update-value" header="src/app/name-editor/name-editor.component.ts (update value)">
</code-example> </code-example>
Update the template with a button to simulate a name update. When you click the **Update Name** button, the value entered in the form control element is reflected as its current value. Update the template with a button to simulate a name update. When you click the **Update Name** button, the value entered in the form control element is reflected as its current value.
<code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="update-value" linenums="false" title="src/app/name-editor/name-editor.component.html (update value)"> <code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="update-value" linenums="false" header="src/app/name-editor/name-editor.component.html (update value)">
</code-example> </code-example>
@ -142,7 +142,7 @@ Generate a `ProfileEditor` component and import the `FormGroup` and `FormControl
</code-example> </code-example>
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="imports" title="src/app/profile-editor/profile-editor.component.ts (imports)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="imports" header="src/app/profile-editor/profile-editor.component.ts (imports)">
</code-example> </code-example>
@ -152,7 +152,7 @@ Create a property in the component class named `profileForm` and set the propert
For the profile form, add two form control instances with the names `firstName` and `lastName`. For the profile form, add two form control instances with the names `firstName` and `lastName`.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="formgroup" title="src/app/profile-editor/profile-editor.component.ts (form group)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="formgroup" header="src/app/profile-editor/profile-editor.component.ts (form group)">
</code-example> </code-example>
@ -162,7 +162,7 @@ The individual form controls are now collected within a group. A `FormGroup` ins
A form group tracks the status and changes for each of its controls, so if one of the controls changes, the parent control also emits a new status or value change. The model for the group is maintained from its members. After you define the model, you must update the template to reflect the model in the view. A form group tracks the status and changes for each of its controls, so if one of the controls changes, the parent control also emits a new status or value change. The model for the group is maintained from its members. After you define the model, you must update the template to reflect the model in the view.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="formgroup" linenums="false" title="src/app/profile-editor/profile-editor.component.html (template form group)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="formgroup" linenums="false" header="src/app/profile-editor/profile-editor.component.html (template form group)">
</code-example> </code-example>
@ -174,13 +174,13 @@ The `ProfileEditor` component accepts input from the user, but in a real scenari
Add an `ngSubmit` event listener to the `form` tag with the `onSubmit()` callback method. Add an `ngSubmit` event listener to the `form` tag with the `onSubmit()` callback method.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="ng-submit" linenums="false" title="src/app/profile-editor/profile-editor.component.html (submit event)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="ng-submit" linenums="false" header="src/app/profile-editor/profile-editor.component.html (submit event)">
</code-example> </code-example>
The `onSubmit()` method in the `ProfileEditor` component captures the current value of `profileForm`. Use `EventEmitter` to keep the form encapsulated and to provide the form value outside the component. The following example uses `console.warn` to log a message to the browser console. The `onSubmit()` method in the `ProfileEditor` component captures the current value of `profileForm`. Use `EventEmitter` to keep the form encapsulated and to provide the form value outside the component. The following example uses `console.warn` to log a message to the browser console.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="on-submit" title="src/app/profile-editor/profile-editor.component.ts (submit method)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="on-submit" header="src/app/profile-editor/profile-editor.component.ts (submit method)">
</code-example> </code-example>
@ -188,7 +188,7 @@ The `submit` event is emitted by the `form` tag using the native DOM event. You
Use a `button` element to add a button to the bottom of the form to trigger the form submission. Use a `button` element to add a button to the bottom of the form to trigger the form submission.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="submit-button" linenums="false" title="src/app/profile-editor/profile-editor.component.html (submit button)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="submit-button" linenums="false" header="src/app/profile-editor/profile-editor.component.html (submit button)">
</code-example> </code-example>
@ -202,7 +202,7 @@ Use a `button` element to add a button to the bottom of the form to trigger the
To display the `ProfileEditor` component that contains the form, add it to a component template. To display the `ProfileEditor` component that contains the form, add it to a component template.
<code-example path="reactive-forms/src/app/app.component.1.html" region="app-profile-editor" linenums="false" title="src/app/app.component.html (profile editor)"> <code-example path="reactive-forms/src/app/app.component.1.html" region="app-profile-editor" linenums="false" header="src/app/app.component.html (profile editor)">
</code-example> </code-example>
@ -220,7 +220,7 @@ When building complex forms, managing the different areas of information is easi
An address is a good example of information that can be grouped together. Form groups can accept both form control and form group instances as children. This makes composing complex form models easier to maintain and logically group together. To create a nested group in `profileForm`, add a nested `address` element to the form group instance. An address is a good example of information that can be grouped together. Form groups can accept both form control and form group instances as children. This makes composing complex form models easier to maintain and logically group together. To create a nested group in `profileForm`, add a nested `address` element to the form group instance.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="nested-formgroup" linenums="false" title="src/app/profile-editor/profile-editor.component.ts (nested form group)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="nested-formgroup" linenums="false" header="src/app/profile-editor/profile-editor.component.ts (nested form group)">
</code-example> </code-example>
@ -232,7 +232,7 @@ After you update the model in the component class, update the template to connec
Add the `address` form group containing the `firstName` and `lastName` fields to the `ProfileEditor` template. Add the `address` form group containing the `firstName` and `lastName` fields to the `ProfileEditor` template.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="formgroupname" linenums="false" title="src/app/profile-editor/profile-editor.component.html (template nested form group)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="formgroupname" linenums="false" header="src/app/profile-editor/profile-editor.component.html (template nested form group)">
</code-example> </code-example>
@ -264,13 +264,13 @@ The strict checks of the `setValue()` method help catch nesting errors in comple
In `ProfileEditorComponent`, use the `updateProfile` method with the example below to update the first name and street address for the user. In `ProfileEditorComponent`, use the `updateProfile` method with the example below to update the first name and street address for the user.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="patch-value" title="src/app/profile-editor/profile-editor.component.ts (patch value)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="patch-value" header="src/app/profile-editor/profile-editor.component.ts (patch value)">
</code-example> </code-example>
Simulate an update by adding a button to the template to update the user profile on demand. Simulate an update by adding a button to the template to update the user profile on demand.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="patch-value" linenums="false" title="src/app/profile-editor/profile-editor.component.html (update value)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="patch-value" linenums="false" header="src/app/profile-editor/profile-editor.component.html (update value)">
</code-example> </code-example>
@ -286,7 +286,7 @@ The following section refactors the `ProfileEditor` component to use the form bu
Import the `FormBuilder` class from the `@angular/forms` package. Import the `FormBuilder` class from the `@angular/forms` package.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="form-builder-imports" title="src/app/profile-editor/profile-editor.component.ts (import)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="form-builder-imports" header="src/app/profile-editor/profile-editor.component.ts (import)">
</code-example> </code-example>
@ -294,7 +294,7 @@ Import the `FormBuilder` class from the `@angular/forms` package.
The `FormBuilder` service is an injectable provider that is provided with the reactive forms module. Inject this dependency by adding it to the component constructor. The `FormBuilder` service is an injectable provider that is provided with the reactive forms module. Inject this dependency by adding it to the component constructor.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="inject-form-builder" title="src/app/profile-editor/profile-editor.component.ts (constructor)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="inject-form-builder" header="src/app/profile-editor/profile-editor.component.ts (constructor)">
</code-example> </code-example>
@ -304,7 +304,7 @@ The `FormBuilder` service has three methods: `control()`, `group()`, and `array(
Use the `group` method to create the `profileForm` controls. Use the `group` method to create the `profileForm` controls.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="form-builder" title="src/app/profile-editor/profile-editor.component.ts (form builder)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="form-builder" header="src/app/profile-editor/profile-editor.component.ts (form builder)">
</code-example> </code-example>
@ -320,11 +320,11 @@ Compare using the form builder to creating the instances manually.
<code-tabs> <code-tabs>
<code-pane path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="formgroup-compare" title="src/app/profile-editor/profile-editor.component.ts (instances)"> <code-pane path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="formgroup-compare" header="src/app/profile-editor/profile-editor.component.ts (instances)">
</code-pane> </code-pane>
<code-pane path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="formgroup-compare" title="src/app/profile-editor/profile-editor.component.ts (form builder)"> <code-pane path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="formgroup-compare" header="src/app/profile-editor/profile-editor.component.ts (form builder)">
</code-pane> </code-pane>
@ -340,7 +340,7 @@ Reactive forms include a set of validator functions for common use cases. These
Import the `Validators` class from the `@angular/forms` package. Import the `Validators` class from the `@angular/forms` package.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="validator-imports" title="src/app/profile-editor/profile-editor.component.ts (import)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="validator-imports" header="src/app/profile-editor/profile-editor.component.ts (import)">
</code-example> </code-example>
@ -350,13 +350,13 @@ The most common validation is making a field required. This section describes ho
In the `ProfileEditor` component, add the `Validators.required` static method as the second item in the array for the `firstName` control. In the `ProfileEditor` component, add the `Validators.required` static method as the second item in the array for the `firstName` control.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="required-validator" title="src/app/profile-editor/profile-editor.component.ts (required validator)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="required-validator" header="src/app/profile-editor/profile-editor.component.ts (required validator)">
</code-example> </code-example>
HTML5 has a set of built-in attributes that you can use for native validation, including `required`, `minlength`, and `maxlength`. You can take advantage of these optional attributes on your form input elements. Add the `required` attribute to the `firstName` input element. HTML5 has a set of built-in attributes that you can use for native validation, including `required`, `minlength`, and `maxlength`. You can take advantage of these optional attributes on your form input elements. Add the `required` attribute to the `firstName` input element.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="required-attribute" linenums="false" title="src/app/profile-editor/profile-editor.component.html (required attribute)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="required-attribute" linenums="false" header="src/app/profile-editor/profile-editor.component.html (required attribute)">
</code-example> </code-example>
@ -372,7 +372,7 @@ When you add a required field to the form control, its initial status is invalid
Display the current status of `profileForm` using interpolation. Display the current status of `profileForm` using interpolation.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="display-status" linenums="false" title="src/app/profile-editor/profile-editor.component.html (display status)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="display-status" linenums="false" header="src/app/profile-editor/profile-editor.component.html (display status)">
</code-example> </code-example>
@ -392,7 +392,7 @@ For more on form validation, visit the [Form Validation](guide/form-validation)
Import the `FormArray` class from `@angular/forms` to use for type information. The `FormBuilder` service is ready to create a `FormArray` instance. Import the `FormArray` class from `@angular/forms` to use for type information. The `FormBuilder` service is ready to create a `FormArray` instance.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="form-array-imports" title="src/app/profile-editor/profile-editor.component.ts (import)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.2.ts" region="form-array-imports" header="src/app/profile-editor/profile-editor.component.ts (import)">
</code-example> </code-example>
@ -402,7 +402,7 @@ You can initialize a form array with any number of controls, from zero to many,
Use the `FormBuilder.array()` method to define the array, and the `FormBuilder.control()` method to populate the array with an initial control. Use the `FormBuilder.array()` method to define the array, and the `FormBuilder.control()` method to populate the array with an initial control.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="aliases" title="src/app/profile-editor/profile-editor.component.ts (aliases form array)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="aliases" header="src/app/profile-editor/profile-editor.component.ts (aliases form array)">
</code-example> </code-example>
@ -414,7 +414,7 @@ A getter provides easy access to the aliases in the form array instance compared
Use the getter syntax to create an `aliases` class property to retrieve the alias's form array control from the parent form group. Use the getter syntax to create an `aliases` class property to retrieve the alias's form array control from the parent form group.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="aliases-getter" title="src/app/profile-editor/profile-editor.component.ts (aliases getter)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="aliases-getter" header="src/app/profile-editor/profile-editor.component.ts (aliases getter)">
</code-example> </code-example>
@ -426,7 +426,7 @@ Use the getter syntax to create an `aliases` class property to retrieve the alia
Define a method to dynamically insert an alias control into the alias's form array. The `FormArray.push()` method inserts the control as a new item in the array. Define a method to dynamically insert an alias control into the alias's form array. The `FormArray.push()` method inserts the control as a new item in the array.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="add-alias" title="src/app/profile-editor/profile-editor.component.ts (add alias)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="add-alias" header="src/app/profile-editor/profile-editor.component.ts (add alias)">
</code-example> </code-example>
@ -438,7 +438,7 @@ To attach the aliases from your form model, you must add it to the template. Sim
Add the template HTML below after the `<div>` closing the `formGroupName` element. Add the template HTML below after the `<div>` closing the `formGroupName` element.
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="formarrayname" linenums="false" title="src/app/profile-editor/profile-editor.component.html (aliases form array template)"> <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.html" region="formarrayname" linenums="false" header="src/app/profile-editor/profile-editor.component.html (aliases form array template)">
</code-example> </code-example>

View File

@ -65,68 +65,34 @@ Disclaimer: The dates are offered as general guidance and may be adjusted by us
The following table contains our current target release dates for the next two major versions of Angular: The following table contains our current target release dates for the next two major versions of Angular:
Date | Stable Release | Compatibility Date | Stable Release | Compatibility
---------------------- | -------------- | ---------------- ---------------------- | -------------- | -------------
September/October 2018 | 7.0.0 | ^6.0.0
March/April 2019 | 8.0.0 | ^7.0.0 March/April 2019 | 8.0.0 | ^7.0.0
September/October 2019 | 9.0.0 | ^8.0.0
Compatiblity note: The primary goal of the backwards compatibility promise is to ensure that changes in the core framework and tooling don't break the existing ecosystem of components and applications and don't put undue upgrade/migration burden on Angular application and component authors. Compatibility note: The primary goal of the backward compatibility promise is to ensure that changes in the core framework and tooling don't break the existing ecosystem of components and applications and don't put undue upgrade/migration burden on Angular application and component authors.
{@a lts} {@a lts}
{@a support} {@a support}
## Support policy ## Support policy and schedule
All of our major releases are supported for 18 months. All of our major releases are supported for 18 months.
* 6 months of active support, during which regularly-scheduled updates and patches are released, as described above in [Release frequency](#frequency "Release frequency"). * 6 months of *active support*, during which regularly-scheduled updates and patches are released.
* 12 months of long-term support (LTS). During the LTS period, only critical fixes and security patches will be released. * 12 months of *long-term support (LTS)*, during which only critical fixes and security patches are released.
The following table provides the support status and key dates for Angular version 4.0.0 and higher. The following table provides the support status and key dates for Angular version 5.0.0 and higher.
<style>
td, th {vertical-align: top} Version | Status | Released | Active Ends | LTS Ends
------- | ------ | ------------ | ------------ | ------------
</style> ^7.0.0 | Active | Oct 18, 2018 | Apr 18, 2019 | Apr 18, 2020
^6.0.0 | LTS | May 3, 2018 | Nov 3, 2018 | Nov 3, 2019
<table> ^5.0.0 | LTS | Nov 1, 2017 | May 1, 2018 | May 1, 2019
<tr>
<th>Version</th>
<th>Status</th>
<th>Release Date</th>
<th>LTS Start Date</th>
<th>LTS End Date</th>
</tr>
<tr>
<td>^4.0.0</td>
<td>LTS</td>
<td>March 23, 2017</td>
<td>September 23, 2017</td>
<td>September 23, 2018</td>
</tr>
<tr>
<td>^5.0.0</td>
<td>LTS</td>
<td>November 1, 2017</td>
<td>May 1, 2018</td>
<td>May 1, 2019</td>
</tr>
<tr>
<td>^6.0.0</td>
<td>Active</td>
<td>May 3, 2018</td>
<td>November 3, 2018</td>
<td>November 3, 2019</td>
</tr>
</table>
LTS for Angular version ^4.0.0 ended on September 23, 2018.
{@a deprecation} {@a deprecation}

View File

@ -15,7 +15,7 @@ The [AnimationOptions](https://angular.io/api/animations/AnimationOptions) inter
To create a reusable animation, use the [`animation()`](https://angular.io/api/animations/animation) method to define an animation in a separate `.ts` file and declare this animation definition as a `const` export variable. You can then import and reuse this animation in any of your app components using the [`useAnimation()`](https://angular.io/api/animations/useAnimation) API. To create a reusable animation, use the [`animation()`](https://angular.io/api/animations/animation) method to define an animation in a separate `.ts` file and declare this animation definition as a `const` export variable. You can then import and reuse this animation in any of your app components using the [`useAnimation()`](https://angular.io/api/animations/useAnimation) API.
<code-example path="animations/src/app/animations.ts" title="src/app/animations.ts" region="reusable" language="typescript" linenums="false"> <code-example path="animations/src/app/animations.ts" header="src/app/animations.ts" region="reusable" language="typescript" linenums="false">
</code-example> </code-example>
In the above code snippet, `transAnimation` is made reusable by declaring it as an export variable. In the above code snippet, `transAnimation` is made reusable by declaring it as an export variable.
@ -27,7 +27,7 @@ In the above code snippet, `transAnimation` is made reusable by declaring it as
You can import the reusable `transAnimation` variable in your component class and reuse it using the `useAnimation()` method as shown below. You can import the reusable `transAnimation` variable in your component class and reuse it using the `useAnimation()` method as shown below.
<code-example path="animations/src/app/open-close.component.3.ts" title="src/app/open-close.component.ts" region="reusable" language="typescript" linenums="false"> <code-example path="animations/src/app/open-close.component.3.ts" header="src/app/open-close.component.ts" region="reusable" language="typescript" linenums="false">
</code-example> </code-example>
## More on Angular animations ## More on Angular animations

View File

@ -43,7 +43,7 @@ Use the `RouterModule.forRoot` method to define a set of routes. Also, import th
The following configuration defines the possible routes for the application. The following configuration defines the possible routes for the application.
<code-example path="animations/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts" region="route-animation-data" language="typescript"> <code-example path="animations/src/app/app.module.ts" linenums="false" header="src/app/app.module.ts" region="route-animation-data" language="typescript">
</code-example> </code-example>
The `home` and `about` paths are associated with the `HomeComponent` and `AboutComponent` views. The route configuration tells the Angular router to instantiate the `HomeComponent` and `AboutComponent` views when the navigation matches the corresponding path. The `home` and `about` paths are associated with the `HomeComponent` and `AboutComponent` views. The route configuration tells the Angular router to instantiate the `HomeComponent` and `AboutComponent` views when the navigation matches the corresponding path.
@ -62,12 +62,12 @@ After configuring the routes, tell the Angular router where to render the views
The `<router-outlet>` container has an attribute directive that contains data about active routes and their states, based on the `data` property that we set in the route configuration. The `<router-outlet>` container has an attribute directive that contains data about active routes and their states, based on the `data` property that we set in the route configuration.
<code-example path="animations/src/app/app.component.html" title="src/app/app.component.html" region="route-animations-outlet"> <code-example path="animations/src/app/app.component.html" header="src/app/app.component.html" region="route-animations-outlet">
</code-example> </code-example>
`AppComponent` defines a method that can detect when a view changes. The method assigns an animation state value to the animation trigger (`@routeAnimation`) based on the route configuration `data` property value. Here's an example of an `AppComponent` method that detects when a route change happens. `AppComponent` defines a method that can detect when a view changes. The method assigns an animation state value to the animation trigger (`@routeAnimation`) based on the route configuration `data` property value. Here's an example of an `AppComponent` method that detects when a route change happens.
<code-example path="animations/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts" region="prepare-router-outlet" language="typescript"> <code-example path="animations/src/app/app.component.ts" linenums="false" header="src/app/app.component.ts" region="prepare-router-outlet" language="typescript">
</code-example> </code-example>
Here, the `prepareRoute()` method takes the value of the output directive (established through `#outlet="outlet"`) and returns a string value representing the state of the animation based on the custom data of the current active route. You can use this data to control which transition to execute for each route. Here, the `prepareRoute()` method takes the value of the output directive (established through `#outlet="outlet"`) and returns a string value representing the state of the animation based on the custom data of the current active route. You can use this data to control which transition to execute for each route.
@ -79,7 +79,7 @@ Animations can be defined directly inside your components. For this example we a
The following code snippet defines a reusable animation named `slideInAnimation`. The following code snippet defines a reusable animation named `slideInAnimation`.
<code-example path="animations/src/app/animations.ts" linenums="false" title="src/app/animations.ts" region="route-animations" language="typescript"> <code-example path="animations/src/app/animations.ts" linenums="false" header="src/app/animations.ts" region="route-animations" language="typescript">
</code-example> </code-example>
The animation definition does several things: The animation definition does several things:
@ -97,14 +97,14 @@ A route change activates the animation trigger, and a transition matching the st
Make the animation definition available in your application by adding the reusable animation (`slideInAnimation`) to the `animations` metadata of the `AppComponent`. Make the animation definition available in your application by adding the reusable animation (`slideInAnimation`) to the `animations` metadata of the `AppComponent`.
<code-example path="animations/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts" region="define" language="typescript"> <code-example path="animations/src/app/app.component.ts" linenums="false" header="src/app/app.component.ts" region="define" language="typescript">
</code-example> </code-example>
### Styling the host and child components ### Styling the host and child components
During a transition, a new view is inserted directly after the old one and both elements appear on screen at the same time. To prevent this, apply additional styling to the host view, and to the removed and inserted child views. The host view must use relative positioning, and the child views must use absolute positioning. Adding styling to the views animates the containers in place, without the DOM moving things around. During a transition, a new view is inserted directly after the old one and both elements appear on screen at the same time. To prevent this, apply additional styling to the host view, and to the removed and inserted child views. The host view must use relative positioning, and the child views must use absolute positioning. Adding styling to the views animates the containers in place, without the DOM moving things around.
<code-example path="animations/src/app/animations.ts" linenums="false" title="src/app/animations.ts" region="style-view" language="typescript"> <code-example path="animations/src/app/animations.ts" linenums="false" header="src/app/animations.ts" region="style-view" language="typescript">
</code-example> </code-example>
### Querying the view containers ### Querying the view containers
@ -113,7 +113,7 @@ Use the `query()` method to find and animate elements within the current host co
Let's assume that we are routing from the *Home => About*. Let's assume that we are routing from the *Home => About*.
<code-example path="animations/src/app/animations.ts" linenums="false" title="src/app/animations.ts" region="query" language="typescript" linenums="false"> <code-example path="animations/src/app/animations.ts" linenums="false" header="src/app/animations.ts" region="query" language="typescript" linenums="false">
</code-example> </code-example>
The animation code does the following after styling the views: The animation code does the following after styling the views:

File diff suppressed because it is too large Load Diff

View File

@ -15,13 +15,13 @@ RxJS provides an implementation of the `Observable` type, which is needed until
RxJS offers a number of functions that can be used to create new observables. These functions can simplify the process of creating observables from things such as events, timers, promises, and so on. For example: RxJS offers a number of functions that can be used to create new observables. These functions can simplify the process of creating observables from things such as events, timers, promises, and so on. For example:
<code-example path="rx-library/src/simple-creation.ts" region="promise" title="Create an observable from a promise"></code-example> <code-example path="rx-library/src/simple-creation.ts" region="promise" header="Create an observable from a promise"></code-example>
<code-example path="rx-library/src/simple-creation.ts" region="interval" title="Create an observable from a counter"></code-example> <code-example path="rx-library/src/simple-creation.ts" region="interval" header="Create an observable from a counter"></code-example>
<code-example path="rx-library/src/simple-creation.ts" region="event" title="Create an observable from an event"></code-example> <code-example path="rx-library/src/simple-creation.ts" region="event" header="Create an observable from an event"></code-example>
<code-example path="rx-library/src/simple-creation.ts" region="ajax" title="Create an observable that creates an AJAX request"></code-example> <code-example path="rx-library/src/simple-creation.ts" region="ajax" header="Create an observable that creates an AJAX request"></code-example>
## Operators ## Operators
@ -29,7 +29,7 @@ Operators are functions that build on the observables foundation to enable sophi
Operators take configuration options, and they return a function that takes a source observable. When executing this returned function, the operator observes the source observables emitted values, transforms them, and returns a new observable of those transformed values. Here is a simple example: Operators take configuration options, and they return a function that takes a source observable. When executing this returned function, the operator observes the source observables emitted values, transforms them, and returns a new observable of those transformed values. Here is a simple example:
<code-example path="rx-library/src/operators.ts" title="Map operator"></code-example> <code-example path="rx-library/src/operators.ts" header="Map operator"></code-example>
You can use _pipes_ to link operators together. Pipes let you combine multiple functions into a single function. The `pipe()` function takes as its arguments the functions you want to combine, and returns a new function that, when executed, runs the composed functions in sequence. You can use _pipes_ to link operators together. Pipes let you combine multiple functions into a single function. The `pipe()` function takes as its arguments the functions you want to combine, and returns a new function that, when executed, runs the composed functions in sequence.
@ -37,11 +37,11 @@ A set of operators applied to an observable is a recipe&mdash;that is, a set of
Heres an example: Heres an example:
<code-example path="rx-library/src/operators.1.ts" title="Standalone pipe function"></code-example> <code-example path="rx-library/src/operators.1.ts" header="Standalone pipe function"></code-example>
The `pipe()` function is also a method on the RxJS `Observable`, so you use this shorter form to define the same operation: The `pipe()` function is also a method on the RxJS `Observable`, so you use this shorter form to define the same operation:
<code-example path="rx-library/src/operators.2.ts" title="Observable.pipe function"></code-example> <code-example path="rx-library/src/operators.2.ts" header="Observable.pipe function"></code-example>
### Common operators ### Common operators
@ -68,7 +68,7 @@ For instance, suppose you have an observable that makes an API request and maps
Here's an example of using the `catchError` operator to do this: Here's an example of using the `catchError` operator to do this:
<code-example path="rx-library/src/error-handling.ts" title="catchError operator"></code-example> <code-example path="rx-library/src/error-handling.ts" header="catchError operator"></code-example>
### Retry failed observable ### Retry failed observable
@ -78,7 +78,7 @@ Use the `retry` operator before the `catchError` operator. It resubscribes to th
The following converts the previous example to retry the request before catching the error: The following converts the previous example to retry the request before catching the error:
<code-example path="rx-library/src/retry-on-error.ts" title="retry operator"></code-example> <code-example path="rx-library/src/retry-on-error.ts" header="retry operator"></code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -94,4 +94,4 @@ This can be useful when scanning through code and looking for observable values.
For example: For example:
<code-example path="rx-library/src/naming-convention.ts" title="Naming observables"></code-example> <code-example path="rx-library/src/naming-convention.ts" header="Naming observables"></code-example>

View File

@ -98,7 +98,7 @@ The following template binds the value of `htmlSnippet`, once by interpolating i
content, and once by binding it to the `innerHTML` property of an element: content, and once by binding it to the `innerHTML` property of an element:
<code-example path="security/src/app/inner-html-binding.component.html" title="src/app/inner-html-binding.component.html"> <code-example path="security/src/app/inner-html-binding.component.html" header="src/app/inner-html-binding.component.html">
</code-example> </code-example>
@ -112,7 +112,7 @@ a value that an attacker might control into `innerHTML` normally causes an XSS
vulnerability. For example, code contained in a `<script>` tag is executed: vulnerability. For example, code contained in a `<script>` tag is executed:
<code-example path="security/src/app/inner-html-binding.component.ts" linenums="false" title="src/app/inner-html-binding.component.ts (class)" region="class"> <code-example path="security/src/app/inner-html-binding.component.ts" linenums="false" header="src/app/inner-html-binding.component.ts (class)" region="class">
</code-example> </code-example>
@ -200,7 +200,7 @@ your intended use of the value. Imagine that the following template needs to bin
`javascript:alert(...)` call: `javascript:alert(...)` call:
<code-example path="security/src/app/bypass-security.component.html" linenums="false" title="src/app/bypass-security.component.html (URL)" region="URL"> <code-example path="security/src/app/bypass-security.component.html" linenums="false" header="src/app/bypass-security.component.html (URL)" region="URL">
</code-example> </code-example>
@ -211,7 +211,7 @@ in development mode, logs this action to the console. To prevent
this, mark the URL value as a trusted URL using the `bypassSecurityTrustUrl` call: this, mark the URL value as a trusted URL using the `bypassSecurityTrustUrl` call:
<code-example path="security/src/app/bypass-security.component.ts" linenums="false" title="src/app/bypass-security.component.ts (trust-url)" region="trust-url"> <code-example path="security/src/app/bypass-security.component.ts" linenums="false" header="src/app/bypass-security.component.ts (trust-url)" region="trust-url">
</code-example> </code-example>
@ -231,13 +231,13 @@ could execute. So call a method on the controller to construct a trusted video U
Angular to allow binding into `<iframe src>`: Angular to allow binding into `<iframe src>`:
<code-example path="security/src/app/bypass-security.component.html" linenums="false" title="src/app/bypass-security.component.html (iframe)" region="iframe"> <code-example path="security/src/app/bypass-security.component.html" linenums="false" header="src/app/bypass-security.component.html (iframe)" region="iframe">
</code-example> </code-example>
<code-example path="security/src/app/bypass-security.component.ts" linenums="false" title="src/app/bypass-security.component.ts (trust-video-url)" region="trust-video-url"> <code-example path="security/src/app/bypass-security.component.ts" linenums="false" header="src/app/bypass-security.component.ts (trust-video-url)" region="trust-video-url">
</code-example> </code-example>

View File

@ -24,7 +24,7 @@ The `SwUpdate` service supports four separate operations:
The two update events, `available` and `activated`, are `Observable` properties of `SwUpdate`: The two update events, `available` and `activated`, are `Observable` properties of `SwUpdate`:
<code-example path="service-worker-getting-started/src/app/log-update.service.ts" linenums="false" title="log-update.service.ts" region="sw-update"> </code-example> <code-example path="service-worker-getting-started/src/app/log-update.service.ts" linenums="false" header="log-update.service.ts" region="sw-update"> </code-example>
You can use these events to notify the user of a pending update or to refresh their pages when the code they are running is out of date. You can use these events to notify the user of a pending update or to refresh their pages when the code they are running is out of date.
@ -35,7 +35,7 @@ It's possible to ask the service worker to check if any updates have been deploy
Do this with the `checkForUpdate()` method: Do this with the `checkForUpdate()` method:
<code-example path="service-worker-getting-started/src/app/check-for-update.service.ts" linenums="false" title="check-for-update.service.ts" region="sw-check-update"> </code-example> <code-example path="service-worker-getting-started/src/app/check-for-update.service.ts" linenums="false" header="check-for-update.service.ts" region="sw-check-update"> </code-example>
This method returns a `Promise` which indicates that the update check has completed successfully, though it does not indicate whether an update was discovered as a result of the check. Even if one is found, the service worker must still successfully download the changed files, which can fail. If successful, the `available` event will indicate availability of a new version of the app. This method returns a `Promise` which indicates that the update check has completed successfully, though it does not indicate whether an update was discovered as a result of the check. Even if one is found, the service worker must still successfully download the changed files, which can fail. If successful, the `available` event will indicate availability of a new version of the app.
@ -44,7 +44,7 @@ This method returns a `Promise` which indicates that the update check has comple
If the current tab needs to be updated to the latest app version immediately, it can ask to do so with the `activateUpdate()` method: If the current tab needs to be updated to the latest app version immediately, it can ask to do so with the `activateUpdate()` method:
<code-example path="service-worker-getting-started/src/app/prompt-update.service.ts" linenums="false" title="prompt-update.service.ts" region="sw-activate"> </code-example> <code-example path="service-worker-getting-started/src/app/prompt-update.service.ts" linenums="false" header="prompt-update.service.ts" region="sw-activate"> </code-example>
Doing this could break lazy-loading into currently running apps, especially if the lazy-loaded chunks use filenames with hashes, which change every version. Doing this could break lazy-loading into currently running apps, especially if the lazy-loaded chunks use filenames with hashes, which change every version.

View File

@ -9,7 +9,7 @@ A basic understanding of the following:
The `src/ngsw-config.json` configuration file specifies which files and data URLs the Angular The `src/ngsw-config.json` configuration file specifies which files and data URLs the Angular
service worker should cache and how it should update the cached files and data. The service worker should cache and how it should update the cached files and data. The
CLI processes the configuration file during `ng build --prod`. Manually, you can process [Angular CLI](cli) processes the configuration file during `ng build --prod`. Manually, you can process
it with the `ngsw-config` tool: it with the `ngsw-config` tool:
```sh ```sh
@ -161,7 +161,15 @@ This section defines the policy by which matching requests will be cached.
For example, the string `3d12h` will cache content for up to three and a half days. For example, the string `3d12h` will cache content for up to three and a half days.
#### `timeout` #### `timeout`
This duration string specifies the network timeout. The network timeout is how long the Angular service worker will wait for the network to respond before using a cached response, if configured to do so. This duration string specifies the network timeout. The network timeout is how long the Angular service worker will wait for the network to respond before using a cached response, if configured to do so. `timeout` is a duration string, using the following unit suffixes:
* `d`: days
* `h`: hours
* `m`: minutes
* `s`: seconds
* `u`: milliseconds
For example, the string `5s30u` will translate to five seconds and 30 milliseconds of network timeout.
#### `strategy` #### `strategy`

View File

@ -55,7 +55,7 @@ gets the correct content.
To ensure resource integrity, the Angular service worker validates To ensure resource integrity, the Angular service worker validates
the hashes of all resources for which it has a hash. Typically for the hashes of all resources for which it has a hash. Typically for
a CLI app, this is everything in the `dist` directory covered by an app created with the [Angular CLI](cli), this is everything in the `dist` directory covered by
the user's `src/ngsw-config.json` configuration. the user's `src/ngsw-config.json` configuration.
If a particular file fails validation, the Angular service worker If a particular file fails validation, the Angular service worker

View File

@ -1,15 +1,11 @@
# Getting started with service workers # Getting started with service workers
This document explains how to enable Angular service worker support in your CLI projects. It then uses a simple example to show you a service worker in action, demonstrating loading and basic caching. This document explains how to enable Angular service worker support in projects that you created with the [Angular CLI](cli). It then uses a simple example to show you a service worker in action, demonstrating loading and basic caching.
#### Prerequisites #### Prerequisites
A basic understanding of the following: A basic understanding of the information in [Introduction to Angular service workers](guide/service-worker-intro).
* [Introduction to Angular service workers](guide/service-worker-intro).
* Angular v6, including Angular CLI v6.
<hr />
## Adding a service worker to your project ## Adding a service worker to your project

View File

@ -31,7 +31,7 @@ Installing the Angular service worker is as simple as including an `NgModule`. I
## Prerequisites ## Prerequisites
Your application must run in a web browser that supports service workers. Currently, the latest versions of Chrome and Firefox are supported. To learn about other browsers that are service worker ready, see the [Can I Use](http://caniuse.com/#feat=serviceworkers) page. Your application must run in a web browser that supports service workers. Currently, service workers are supported in the latest versions of Chrome, Firefox, Edge, Safari, Opera, UC Browser (Android version) and Samsung Internet. Browsers like IE and Opera Mini do not provide the support. To learn more about other browsers that are service worker ready, see the [Can I Use](https://caniuse.com/#feat=serviceworkers) page and [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API).
## Related resources ## Related resources

View File

@ -43,7 +43,7 @@ for getting and setting the current HTML document title:
You can inject the `Title` service into the root `AppComponent` and expose a bindable `setTitle` method that calls it: You can inject the `Title` service into the root `AppComponent` and expose a bindable `setTitle` method that calls it:
<code-example path="set-document-title/src/app/app.component.ts" region="class" title="src/app/app.component.ts (class)" linenums="false"></code-example> <code-example path="set-document-title/src/app/app.component.ts" region="class" header="src/app/app.component.ts (class)" linenums="false"></code-example>
Bind that method to three anchor tags and voilà! Bind that method to three anchor tags and voilà!
@ -54,9 +54,9 @@ Bind that method to three anchor tags and voilà!
Here's the complete solution: Here's the complete solution:
<code-tabs> <code-tabs>
<code-pane title="src/main.ts" path="set-document-title/src/main.ts"></code-pane> <code-pane header="src/main.ts" path="set-document-title/src/main.ts"></code-pane>
<code-pane title="src/app/app.module.ts" path="set-document-title/src/app/app.module.ts"></code-pane> <code-pane header="src/app/app.module.ts" path="set-document-title/src/app/app.module.ts"></code-pane>
<code-pane title="src/app/app.component.ts" path="set-document-title/src/app/app.component.ts"></code-pane> <code-pane header="src/app/app.component.ts" path="set-document-title/src/app/app.component.ts"></code-pane>
</code-tabs> </code-tabs>
## Why provide the `Title` service in `bootstrap` ## Why provide the `Title` service in `bootstrap`

View File

@ -1,360 +0,0 @@
# Anatomy of the Setup Project
The documentation [setup](guide/setup) procedures install a _lot_ of files.
Most of them can be safely ignored.
Application files _inside the_ **`src/`** and **`e2e/`** folders matter most to developers.
Files _outside_ those folders condition the development environment.
They rarely change and you may never view or modify them.
If you do, this page can help you understand their purpose.
<style>
td, th {vertical-align: top}
</style>
<table width="100%">
<col width="10%">
</col>
<col width="90%">
</col>
<tr>
<th>
File
</th>
<th>
Purpose
</th>
</tr>
<tr>
<td>
<code>src/app/</code>
</td>
<td>
Angular application files go here.
Ships with the "Hello Angular" sample's
`AppComponent`, `AppModule`, a component unit test (`app.component.spec.ts`), and
the bootstrap file, `main.ts`.
Try the <live-example name="setup">sample application</live-example>
and the <live-example name="setup" stackblitz="quickstart-specs">unit test</live-example>
as _live examples_.
</td>
</tr>
<tr>
<td>
<code>e2e/</code>
</td>
<td>
_End-to-end_ (e2e) tests of the application,
written in Jasmine and run by the
<a href="http://www.protractortest.org/" title="Protractor: end-to-end testing for Angular">protractor</a>
e2e test runner.
Initialized with an e2e test for the "Hello Angular" sample.
</td>
</tr>
<tr>
<td>
<code>node_modules/</code>
</td>
<td>
The _npm_ packages installed with the `npm install` command.
</td>
</tr>
<tr>
<td>
<code>.editorconfig<br>
.git/<br>
.gitignore<br>
.travis.yml</code>
</td>
<td>
Tooling configuration files and folders.
Ignore them until you have a compelling reason to do otherwise.
</td>
</tr>
<tr>
<td>
<code>CHANGELOG.md</code>
</td>
<td>
The history of changes to the _QuickStart_ repository.
Delete or ignore.
</td>
</tr>
<tr>
<td>
<code>favicon.ico</code>
</td>
<td>
The application icon that appears in the browser tab.
</td>
</tr>
<tr>
<td>
<code>index.html</code>
</td>
<td>
The application host page.
It loads a few essential scripts in a prescribed order.
Then it boots the application, placing the root `AppComponent`
in the custom `<my-app>` body tag.
The same `index.html` satisfies all documentation application samples.
</td>
</tr>
<tr>
<td>
<code>karma.conf.js</code>
</td>
<td>
Configuration for the <a href="https://karma-runner.github.io/1.0/index.html" title="Karma unit test runner">karma</a>
test runner described in the [Testing](guide/testing) guide.
</td>
</tr>
<tr>
<td>
<code>karma-test-shim.js</code>
</td>
<td>
Script to run <a href="https://karma-runner.github.io/1.0/index.html" title="Karma unit test runner">karma</a>
with SystemJS as described in the [Testing](guide/testing) guide.
</td>
</tr>
<tr>
<td>
<code>non-essential-files.txt</code>
</td>
<td>
A list of files that you can delete if you want to purge your setup of the
original QuickStart Seed testing and git maintenance artifacts.
See instructions in the optional
[_Deleting non-essential files_](guide/setup#non-essential "Setup: Deleting non-essential files") section.
*Do this only in the beginning to avoid accidentally deleting your own tests and git setup!*
</td>
</tr>
<tr>
<td>
<code>LICENSE</code>
</td>
<td>
The open source MIT license to use this setup code in your application.
</td>
</tr>
<tr>
<td>
<code>package.json</code>
</td>
<td>
Identifies `npm `package dependencies for the project.
Contains command scripts for running the application,
running tests, and more. Enter `npm run` for a listing.
<a href="https://github.com/angular/quickstart/blob/master/README.md#npm-scripts"
title="npm scripts for Angular documentation samples">Read more</a> about them.
</td>
</tr>
<tr>
<td>
<code>protractor.config.js</code>
</td>
<td>
Configuration for the
<a href="http://www.protractortest.org/" title="Protractor: end-to-end testing for Angular">protractor</a>
_end-to-end_ (e2e) test runner.
</td>
</tr>
<tr>
<td>
<code>README.md</code>
</td>
<td>
Instruction for using this git repository in your project.
Worth reading before deleting.
</td>
</tr>
<tr>
<td>
<code>styles.css</code>
</td>
<td>
Global styles for the application. Initialized with an `<h1>` style for the QuickStart demo.
</td>
</tr>
<tr>
<td>
<code>systemjs<br>.config.js</code>
</td>
<td>
Tells the **SystemJS** module loader where to find modules
referenced in JavaScript `import` statements. For example:
<code-example language="ts">
import { Component } from '@angular/core;
</code-example>
Don't touch this file unless you are fully versed in SystemJS configuration.
</td>
</tr>
<tr>
<td>
<code>systemjs<br>.config.extras.js</code>
</td>
<td>
Optional extra SystemJS configuration.
A way to add SystemJS mappings, such as for application _barrels_,
without changing the original `system.config.js`.
</td>
</tr>
<tr>
<td>
<code>tsconfig.json</code>
</td>
<td>
Tells the TypeScript compiler how to transpile TypeScript source files
into JavaScript files that run in all modern browsers.
</td>
</tr>
<tr>
<td>
<code>tslint.json</code>
</td>
<td>
The `npm` installed TypeScript linter inspects your TypeScript code
and complains when you violate one of its rules.
This file defines linting rules favored by the
[Angular style guide](guide/styleguide) and by the authors of the documentation.
</td>
</tr>
</table>

View File

@ -125,7 +125,7 @@ Open a terminal window in the project folder and enter the following commands fo
The **QuickStart seed** contains the same application as the QuickStart playground. The **QuickStart seed** contains the same application as the QuickStart playground.
But its true purpose is to provide a solid foundation for _local_ development. But its true purpose is to provide a solid foundation for _local_ development.
Consequently, there are _many more files_ in the project folder on your machine, Consequently, there are _many more files_ in the project folder on your machine,
most of which you can [learn about later](guide/setup-systemjs-anatomy "Setup Anatomy"). most of which you can [learn about later](guide/file-structure).
@ -171,15 +171,15 @@ Focus on the following three TypeScript (`.ts`) files in the **`/src`** folder.
<code-tabs> <code-tabs>
<code-pane title="src/app/app.component.ts" path="setup/src/app/app.component.ts"> <code-pane header="src/app/app.component.ts" path="setup/src/app/app.component.ts">
</code-pane> </code-pane>
<code-pane title="src/app/app.module.ts" path="setup/src/app/app.module.ts"> <code-pane header="src/app/app.module.ts" path="setup/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="src/main.ts" path="setup/src/main.ts"> <code-pane header="src/main.ts" path="setup/src/main.ts">
</code-pane> </code-pane>
@ -330,7 +330,7 @@ You may need [nvm](https://github.com/creationix/nvm) if you already have projec
Links on almost every documentation page open completed samples in the browser. Links on almost every documentation page open completed samples in the browser.
You can play with the sample code, share your changes with friends, and download and run the code on your own machine. You can play with the sample code, share your changes with friends, and download and run the code on your own machine.
The [QuickStart](guide/quickstart "Angular QuickStart Playground") shows just the `AppComponent` file. The [Getting Started](guide/quickstart "Angular QuickStart Playground") shows just the `AppComponent` file.
It creates the equivalent of `app.module.ts` and `main.ts` internally _for the playground only_. It creates the equivalent of `app.module.ts` and `main.ts` internally _for the playground only_.
so the reader can discover Angular without distraction. so the reader can discover Angular without distraction.
The other samples are based on the QuickStart seed. The other samples are based on the QuickStart seed.
@ -356,3 +356,24 @@ If you develop angular locally with `ng serve`, there will be `websocket` connec
In windows, by default one application can only have 6 websocket connections, <a href="https://msdn.microsoft.com/library/ee330736%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396#websocket_maxconn" title="MSDN WebSocket settings">MSDN WebSocket Settings</a>. In windows, by default one application can only have 6 websocket connections, <a href="https://msdn.microsoft.com/library/ee330736%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396#websocket_maxconn" title="MSDN WebSocket settings">MSDN WebSocket Settings</a>.
So if IE was refreshed manunally or automatically by `ng serve`, sometimes, the websocket will not close properly, when websocket connections exceed limitations, `SecurityError` will be thrown, this error will not affect the angular application, you can just restart IE to clear this error, or modify the windows registry to update the limitations. So if IE was refreshed manunally or automatically by `ng serve`, sometimes, the websocket will not close properly, when websocket connections exceed limitations, `SecurityError` will be thrown, this error will not affect the angular application, you can just restart IE to clear this error, or modify the windows registry to update the limitations.
## Appendix: test using `fakeAsync()/async()`
If you use the `fakeAsync()/async()` helper function to run unit tests (for details, read [testing guide](guide/testing#async-test-with-fakeasync)), you need to import `zone.js/dist/zone-testing` in your test setup file.
<div class="alert is-important">
If you create project with `Angular/CLI`, it is already imported in `src/test.ts`.
</div>
And in the earlier versions of `Angular`, the following files were imported or added in your html file:
```
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
```
You can still load those files separately, but the order is important, you must import `proxy` before `sync-test`, `async-test`, `fake-async-test` and `jasmine-patch`. And you also need to import `sync-test` before `jasmine-patch`, so it is recommended to just import `zone-testing` instead of loading those separated files.

View File

@ -19,7 +19,7 @@ There are two ways to make a service a singleton in Angular:
Beginning with Angular 6.0, the preferred way to create a singleton services is to specify on the service that it should be provided in the application root. This is done by setting `providedIn` to `root` on the service's `@Injectable` decorator: Beginning with Angular 6.0, the preferred way to create a singleton services is to specify on the service that it should be provided in the application root. This is done by setting `providedIn` to `root` on the service's `@Injectable` decorator:
<code-example path="providers/src/app/user.service.0.ts" title="src/app/user.service.0.ts" linenums="false"> </code-example> <code-example path="providers/src/app/user.service.0.ts" header="src/app/user.service.0.ts" linenums="false"> </code-example>
For more detailed information on services, see the [Services](tutorial/toh-pt4) chapter of the For more detailed information on services, see the [Services](tutorial/toh-pt4) chapter of the
@ -69,19 +69,19 @@ the core `UserService`.
In the following example, the optional, injected `UserServiceConfig` In the following example, the optional, injected `UserServiceConfig`
extends the core `UserService`. If a `UserServiceConfig` exists, the `UserService` sets the user name from that config. extends the core `UserService`. If a `UserServiceConfig` exists, the `UserService` sets the user name from that config.
<code-example path="ngmodules/src/app/core/user.service.ts" region="ctor" title="src/app/core/user.service.ts (constructor)" linenums="false"> <code-example path="ngmodules/src/app/core/user.service.ts" region="ctor" header="src/app/core/user.service.ts (constructor)" linenums="false">
</code-example> </code-example>
Here's `forRoot()` that takes a `UserServiceConfig` object: Here's `forRoot()` that takes a `UserServiceConfig` object:
<code-example path="ngmodules/src/app/core/core.module.ts" region="for-root" title="src/app/core/core.module.ts (forRoot)" linenums="false"> <code-example path="ngmodules/src/app/core/core.module.ts" region="for-root" header="src/app/core/core.module.ts (forRoot)" linenums="false">
</code-example> </code-example>
Lastly, call it within the `imports` list of the `AppModule`. Lastly, call it within the `imports` list of the `AppModule`.
<code-example path="ngmodules/src/app/app.module.ts" region="import-for-root" title="src/app/app.module.ts (imports)" linenums="false"> <code-example path="ngmodules/src/app/app.module.ts" region="import-for-root" header="src/app/app.module.ts (imports)" linenums="false">
</code-example> </code-example>
@ -99,7 +99,7 @@ lazy-loaded module imports it too, the app can generate
To guard against a lazy-loaded module re-importing `CoreModule`, add the following `CoreModule` constructor. To guard against a lazy-loaded module re-importing `CoreModule`, add the following `CoreModule` constructor.
<code-example path="ngmodules/src/app/core/core.module.ts" region="ctor" title="src/app/core/core.module.ts" linenums="false"> <code-example path="ngmodules/src/app/core/core.module.ts" region="ctor" header="src/app/core/core.module.ts" linenums="false">
</code-example> </code-example>
@ -130,11 +130,11 @@ Here are the two files in their entirety for reference:
<code-tabs linenums="false"> <code-tabs linenums="false">
<code-pane <code-pane
title="app.module.ts" header="app.module.ts"
path="ngmodules/src/app/app.module.ts"> path="ngmodules/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane <code-pane
title="core.module.ts" header="core.module.ts"
region="whole-core-module" region="whole-core-module"
path="ngmodules/src/app/core/core.module.ts"> path="ngmodules/src/app/core/core.module.ts">
</code-pane> </code-pane>

View File

@ -31,7 +31,7 @@ Structural directives are easy to recognize.
An asterisk (*) precedes the directive attribute name as in this example. An asterisk (*) precedes the directive attribute name as in this example.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif)" region="ngif"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngif)" region="ngif">
</code-example> </code-example>
@ -52,7 +52,7 @@ described in the [_Template Syntax_](guide/template-syntax) guide and seen in sa
Here's an example of them in a template: Here's an example of them in a template:
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (built-in)" region="built-in"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (built-in)" region="built-in">
</code-example> </code-example>
@ -121,7 +121,7 @@ You can [only apply one](guide/structural-directives#one-per-element) _structura
It takes a boolean expression and makes an entire chunk of the DOM appear or disappear. It takes a boolean expression and makes an entire chunk of the DOM appear or disappear.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-true)" region="ngif-true"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngif-true)" region="ngif-true">
</code-example> </code-example>
@ -150,7 +150,7 @@ The component and DOM nodes can be garbage-collected and free up memory.
A directive could hide the unwanted paragraph instead by setting its `display` style to `none`. A directive could hide the unwanted paragraph instead by setting its `display` style to `none`.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (display-none)" region="display-none"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (display-none)" region="display-none">
</code-example> </code-example>
@ -201,7 +201,7 @@ and wondered why it is necessary and what it does.
Here is `*ngIf` displaying the hero's name if `hero` exists. Here is `*ngIf` displaying the hero's name if `hero` exists.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (asterisk)" region="asterisk"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (asterisk)" region="asterisk">
</code-example> </code-example>
@ -211,7 +211,7 @@ The asterisk is "syntactic sugar" for something a bit more complicated.
Internally, Angular translates the `*ngIf` _attribute_ into a `<ng-template>` _element_, wrapped around the host element, like this. Internally, Angular translates the `*ngIf` _attribute_ into a `<ng-template>` _element_, wrapped around the host element, like this.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-template)" region="ngif-template"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngif-template)" region="ngif-template">
</code-example> </code-example>
@ -246,7 +246,7 @@ Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax to `
Here's a full-featured application of `NgFor`, written both ways: Here's a full-featured application of `NgFor`, written both ways:
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (inside-ngfor)" region="inside-ngfor"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (inside-ngfor)" region="inside-ngfor">
</code-example> </code-example>
@ -373,7 +373,7 @@ The Angular _NgSwitch_ is actually a set of cooperating directives: `NgSwitch`,
Here's an example. Here's an example.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngswitch)" region="ngswitch"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngswitch)" region="ngswitch">
</code-example> </code-example>
@ -409,7 +409,7 @@ As with other structural directives, the `NgSwitchCase` and `NgSwitchDefault`
can be desugared into the `<ng-template>` element form. can be desugared into the `<ng-template>` element form.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngswitch-template)" region="ngswitch-template"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngswitch-template)" region="ngswitch-template">
</code-example> </code-example>
@ -444,7 +444,7 @@ those elements disappear.
That's the fate of the middle "Hip!" in the phrase "Hip! Hip! Hooray!". That's the fate of the middle "Hip!" in the phrase "Hip! Hip! Hooray!".
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (template-tag)" region="template-tag"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (template-tag)" region="template-tag">
</code-example> </code-example>
@ -476,7 +476,7 @@ There's often a _root_ element that can and should host the structural directive
The list element (`<li>`) is a typical host element of an `NgFor` repeater. The list element (`<li>`) is a typical host element of an `NgFor` repeater.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngfor-li)" region="ngfor-li"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngfor-li)" region="ngfor-li">
</code-example> </code-example>
@ -486,7 +486,7 @@ When there isn't a host element, you can usually wrap the content in a native HT
such as a `<div>`, and attach the directive to that wrapper. such as a `<div>`, and attach the directive to that wrapper.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif)" region="ngif"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngif)" region="ngif">
</code-example> </code-example>
@ -501,7 +501,7 @@ neither expect nor accommodate the new layout.
For example, suppose you have the following paragraph layout. For example, suppose you have the following paragraph layout.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-span)" region="ngif-span"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngif-span)" region="ngif-span">
</code-example> </code-example>
@ -510,7 +510,7 @@ For example, suppose you have the following paragraph layout.
You also have a CSS style rule that happens to apply to a `<span>` within a `<p>`aragraph. You also have a CSS style rule that happens to apply to a `<span>` within a `<p>`aragraph.
<code-example path="structural-directives/src/app/app.component.css" linenums="false" title="src/app/app.component.css (p-span)" region="p-span"> <code-example path="structural-directives/src/app/app.component.css" linenums="false" header="src/app/app.component.css (p-span)" region="p-span">
</code-example> </code-example>
@ -534,7 +534,7 @@ You can't wrap the _options_ in a conditional `<div>` or a `<span>`.
When you try this, When you try this,
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (select-span)" region="select-span"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (select-span)" region="select-span">
</code-example> </code-example>
@ -559,7 +559,7 @@ because Angular _doesn't put it in the DOM_.
Here's the conditional paragraph again, this time using `<ng-container>`. Here's the conditional paragraph again, this time using `<ng-container>`.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-ngcontainer)" region="ngif-ngcontainer"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (ngif-ngcontainer)" region="ngif-ngcontainer">
</code-example> </code-example>
@ -577,7 +577,7 @@ It renders properly.
Now conditionally exclude a _select_ `<option>` with `<ng-container>`. Now conditionally exclude a _select_ `<option>` with `<ng-container>`.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (select-ngcontainer)" region="select-ngcontainer"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (select-ngcontainer)" region="select-ngcontainer">
</code-example> </code-example>
@ -625,7 +625,7 @@ that does the opposite of `NgIf`.
`UnlessDirective` displays the content when the condition is ***false***. `UnlessDirective` displays the content when the condition is ***false***.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (appUnless-1)" region="appUnless-1"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (appUnless-1)" region="appUnless-1">
</code-example> </code-example>
@ -644,7 +644,7 @@ Creating a directive is similar to creating a component.
Here's how you might begin: Here's how you might begin:
<code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" title="src/app/unless.directive.ts (skeleton)" region="skeleton"> <code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" header="src/app/unless.directive.ts (skeleton)" region="skeleton">
</code-example> </code-example>
@ -679,7 +679,7 @@ and access the _view container_ through a
You inject both in the directive constructor as private variables of the class. You inject both in the directive constructor as private variables of the class.
<code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" title="src/app/unless.directive.ts (ctor)" region="ctor"> <code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" header="src/app/unless.directive.ts (ctor)" region="ctor">
</code-example> </code-example>
@ -702,7 +702,7 @@ Read about `@Input` in the [_Template Syntax_](guide/template-syntax#inputs-outp
<code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" title="src/app/unless.directive.ts (set)" region="set"> <code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" header="src/app/unless.directive.ts (set)" region="set">
</code-example> </code-example>
@ -722,7 +722,7 @@ Nobody reads the `appUnless` property so it doesn't need a getter.
The completed directive code looks like this: The completed directive code looks like this:
<code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" title="src/app/unless.directive.ts (excerpt)" region="no-docs"> <code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" header="src/app/unless.directive.ts (excerpt)" region="no-docs">
</code-example> </code-example>
@ -733,7 +733,7 @@ Add this directive to the `declarations` array of the AppModule.
Then create some HTML to try it. Then create some HTML to try it.
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (appUnless)" region="appUnless"> <code-example path="structural-directives/src/app/app.component.html" linenums="false" header="src/app/app.component.html (appUnless)" region="appUnless">
</code-example> </code-example>
@ -762,31 +762,31 @@ Here is the source from the `src/app/` folder.
<code-tabs> <code-tabs>
<code-pane title="app.component.ts" path="structural-directives/src/app/app.component.ts"> <code-pane header="app.component.ts" path="structural-directives/src/app/app.component.ts">
</code-pane> </code-pane>
<code-pane title="app.component.html" path="structural-directives/src/app/app.component.html"> <code-pane header="app.component.html" path="structural-directives/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane title="app.component.css" path="structural-directives/src/app/app.component.css"> <code-pane header="app.component.css" path="structural-directives/src/app/app.component.css">
</code-pane> </code-pane>
<code-pane title="app.module.ts" path="structural-directives/src/app/app.module.ts"> <code-pane header="app.module.ts" path="structural-directives/src/app/app.module.ts">
</code-pane> </code-pane>
<code-pane title="hero.ts" path="structural-directives/src/app/hero.ts"> <code-pane header="hero.ts" path="structural-directives/src/app/hero.ts">
</code-pane> </code-pane>
<code-pane title="hero-switch.components.ts" path="structural-directives/src/app/hero-switch.components.ts"> <code-pane header="hero-switch.components.ts" path="structural-directives/src/app/hero-switch.components.ts">
</code-pane> </code-pane>
<code-pane title="unless.directive.ts" path="structural-directives/src/app/unless.directive.ts"> <code-pane header="unless.directive.ts" path="structural-directives/src/app/unless.directive.ts">
</code-pane> </code-pane>

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