Compare commits
253 Commits
Author | SHA1 | Date | |
---|---|---|---|
024aba075c | |||
a86d038875 | |||
bc8a93e842 | |||
4c18f637ae | |||
fc189b2577 | |||
778ddb257a | |||
2d4f4b5d12 | |||
912742f1ca | |||
0746485136 | |||
265489518e | |||
00dd566b47 | |||
59fd91d785 | |||
56712aa771 | |||
529e4b1565 | |||
9ff4617956 | |||
8887d75723 | |||
7717ff187a | |||
98b18cd49f | |||
fe23a6e77e | |||
d7c4898081 | |||
98c509fecb | |||
a92f111b66 | |||
de1c44f6e3 | |||
183b079175 | |||
8f8caa13b7 | |||
195dc0748b | |||
2c6f84b25d | |||
8e726f7d7b | |||
2d1102f5bf | |||
0437598609 | |||
bc2bf184a2 | |||
b51ce62c58 | |||
25b532e819 | |||
69c8226a9f | |||
5326537985 | |||
ada486a1dd | |||
563e8e3e56 | |||
dd931c73ec | |||
b8975a90ca | |||
f44161503a | |||
6c55a130b1 | |||
144a624088 | |||
f561f5a460 | |||
916914be13 | |||
9a98de941d | |||
0f1de35604 | |||
d89f57f9d5 | |||
ac5b69f783 | |||
5ddd6dcedd | |||
ad68332fa0 | |||
2880cf9ef1 | |||
64a8584a92 | |||
97897ab738 | |||
9378f44d6d | |||
afa46af4c6 | |||
dbffdcc442 | |||
06d68a1b9f | |||
75dd3c5ca5 | |||
23f56198a5 | |||
69167e4519 | |||
10feafcf27 | |||
3f3fed95be | |||
94433f3b9e | |||
aa753878e6 | |||
3513ae40cc | |||
979e7b6086 | |||
41f008d109 | |||
c950410ee1 | |||
b0fa504d39 | |||
426f9710a0 | |||
ae01c70bba | |||
3341a97154 | |||
2056e1f05c | |||
3938a8be75 | |||
393db94b8d | |||
65744e4ae1 | |||
56bc86992c | |||
9426c02648 | |||
0b356d4163 | |||
a886659444 | |||
3649958595 | |||
8919577c54 | |||
84eff4219e | |||
c11e84ee18 | |||
1ce5a495d3 | |||
1f532aaa5a | |||
e81982ef90 | |||
776bc38999 | |||
7e7ef8ee25 | |||
dd90d92573 | |||
1b862820e9 | |||
1a642231cd | |||
138e0d79cd | |||
f0a43716e2 | |||
2be27fb888 | |||
74f07f40e0 | |||
aa66e84e44 | |||
e1bc3f5c1a | |||
f5b366147b | |||
3147a92ee9 | |||
ffedbde0b3 | |||
e543c734ab | |||
fbe6871a94 | |||
f43cb9398c | |||
1e04df9ac7 | |||
840ca05fe8 | |||
facc9d498d | |||
9d0999027f | |||
c00dd5a3f3 | |||
3908a63381 | |||
20f9e51b8f | |||
232203242a | |||
0ca634e697 | |||
7fd9918024 | |||
b0aacb81d4 | |||
6c850eb031 | |||
0df61ad107 | |||
fa985ac067 | |||
06f9197361 | |||
c2bad1249e | |||
9d69ff8ddd | |||
3fd33f8eb0 | |||
501a243b3f | |||
b91b9efc91 | |||
03718c95ce | |||
0834710c18 | |||
9a9a7de9a4 | |||
ff51691221 | |||
2ad90ab0d3 | |||
c5872e6782 | |||
d20877bf3f | |||
b3089b4963 | |||
880b03101e | |||
451d996414 | |||
ea3669e334 | |||
ea2987c7af | |||
5b823dedcc | |||
80f7c83bdd | |||
53072b10da | |||
30c2f560b1 | |||
18c4976f3b | |||
0139173c7c | |||
f3c9954a68 | |||
e8765352e8 | |||
9e61ad897e | |||
0d81151cbc | |||
70319722a1 | |||
cfa5b6567d | |||
41698bf5fd | |||
23c50e27fc | |||
0ae8ea254a | |||
19deca159b | |||
dc3e8aa0fb | |||
a9222c0ade | |||
ea3127e3f9 | |||
8e30f7b1aa | |||
46d81b48ac | |||
3e51a2cb26 | |||
faf60d9310 | |||
0639cb9de1 | |||
810d025488 | |||
efe49c141a | |||
a3d9878c9d | |||
10213d0ca0 | |||
0e1919c2db | |||
d579b8ce05 | |||
d69ba735ee | |||
2991b1b217 | |||
b18cf21e99 | |||
c17098dae6 | |||
43e3073687 | |||
f28878f92f | |||
a10bdefa8b | |||
2f377dbcdd | |||
e2e7b4943e | |||
b8a1363bb2 | |||
e9e6a58dd0 | |||
5932a79713 | |||
7c6a082afd | |||
8a2fe5b7c9 | |||
c9eb4910eb | |||
a634a5abbc | |||
41225026e4 | |||
e9f2203347 | |||
906b3ec8e7 | |||
1cb0c4644a | |||
9d28a27215 | |||
f04aef48f2 | |||
d249852f4a | |||
707dd59767 | |||
4d2570576a | |||
76e58e6cca | |||
a27066b9d2 | |||
29dfc8f3ac | |||
b5533e0ee5 | |||
b275d378df | |||
96655f7aac | |||
253f509493 | |||
5a02ae2f84 | |||
f860752902 | |||
efa126f157 | |||
715135b117 | |||
c30fc52d99 | |||
434eb971e4 | |||
6e31e22d41 | |||
8fef926cd2 | |||
7698afedb1 | |||
a583d12660 | |||
a867d71ece | |||
84b43daf65 | |||
9b3423b50d | |||
d6041d83ec | |||
a638f504eb | |||
a29c756251 | |||
f206eb94bb | |||
3d6e82eccd | |||
154289305e | |||
469b1e4a9a | |||
7fee1fd442 | |||
0ee5b7efa5 | |||
afff84c03f | |||
23f2a7069f | |||
42260702f7 | |||
eec231d21e | |||
95344d6039 | |||
1c9839e91d | |||
bc1a66e907 | |||
2a83dbb0d8 | |||
4007d00403 | |||
61e32ac3c4 | |||
43ee10fbbd | |||
eb90039ea1 | |||
5d318ff234 | |||
f3361abdd7 | |||
52cbe894e9 | |||
41c2030534 | |||
daee41a40a | |||
68bd45ba87 | |||
0f6407750b | |||
95fca24fd8 | |||
a8f6542115 | |||
c6b618d020 | |||
ad6052e397 | |||
e9d1709156 | |||
b5d3de50cc | |||
734d37b231 | |||
bc2063807c | |||
2a528fcb15 | |||
752b83ac81 | |||
56be3375ec | |||
1b83b3fb15 | |||
14d4625ede | |||
fd880a8de4 |
@ -12,8 +12,8 @@
|
|||||||
## IMPORTANT
|
## IMPORTANT
|
||||||
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of
|
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of
|
||||||
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file.
|
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file.
|
||||||
var_1: &docker_image angular/ngcontainer:0.3.0
|
var_1: &docker_image angular/ngcontainer:0.3.2
|
||||||
var_2: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.3.0
|
var_2: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.3.2
|
||||||
|
|
||||||
# Define common ENV vars
|
# Define common ENV vars
|
||||||
var_3: &define_env_vars
|
var_3: &define_env_vars
|
||||||
@ -80,7 +80,7 @@ jobs:
|
|||||||
|
|
||||||
- run: ls /home/circleci/bazel_repository_cache || true
|
- run: ls /home/circleci/bazel_repository_cache || true
|
||||||
- run: bazel info release
|
- run: bazel info release
|
||||||
- run: bazel run @yarn//:yarn
|
- run: bazel run @nodejs//:yarn
|
||||||
# Use bazel query so that we explicitly ask for all buildable targets to be built as well
|
# Use bazel query so that we explicitly ask for all buildable targets to be built as well
|
||||||
# This avoids waiting for the slowest build target to finish before running the first test
|
# This avoids waiting for the slowest build target to finish before running the first test
|
||||||
# See https://github.com/bazelbuild/bazel/issues/4257
|
# See https://github.com/bazelbuild/bazel/issues/4257
|
||||||
@ -131,7 +131,7 @@ jobs:
|
|||||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||||
- *setup-bazel-remote-cache
|
- *setup-bazel-remote-cache
|
||||||
|
|
||||||
- run: bazel run @yarn//:yarn
|
- run: bazel run @nodejs//:yarn
|
||||||
- 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
|
||||||
@ -149,6 +149,10 @@ 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
|
||||||
|
# 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
|
||||||
|
# on a 4G worker so we use a larger machine here too.
|
||||||
|
resource_class: xlarge
|
||||||
steps:
|
steps:
|
||||||
- *define_env_vars
|
- *define_env_vars
|
||||||
- checkout:
|
- checkout:
|
||||||
|
3
.github/angular-robot.yml
vendored
3
.github/angular-robot.yml
vendored
@ -4,6 +4,7 @@
|
|||||||
size:
|
size:
|
||||||
disabled: false
|
disabled: false
|
||||||
maxSizeIncrease: 1000
|
maxSizeIncrease: 1000
|
||||||
|
circleCiStatusName: "ci/circleci: build-packages-dist"
|
||||||
status:
|
status:
|
||||||
disabled: false
|
disabled: false
|
||||||
context: "ci/angular: size"
|
context: "ci/angular: size"
|
||||||
@ -44,10 +45,12 @@ merge:
|
|||||||
- "packages/language-service/**"
|
- "packages/language-service/**"
|
||||||
- "**/.gitignore"
|
- "**/.gitignore"
|
||||||
- "**/.gitkeep"
|
- "**/.gitkeep"
|
||||||
|
- "**/package.json"
|
||||||
- "**/tsconfig-build.json"
|
- "**/tsconfig-build.json"
|
||||||
- "**/tsconfig.json"
|
- "**/tsconfig.json"
|
||||||
- "**/rollup.config.js"
|
- "**/rollup.config.js"
|
||||||
- "**/BUILD.bazel"
|
- "**/BUILD.bazel"
|
||||||
|
- "packages/**/integrationtest/**"
|
||||||
- "packages/**/test/**"
|
- "packages/**/test/**"
|
||||||
|
|
||||||
# comment that will be added to a PR when there is a conflict, leave empty or set to false to disable
|
# comment that will be added to a PR when there is a conflict, leave empty or set to false to disable
|
||||||
|
10
BUILD.bazel
10
BUILD.bazel
@ -11,7 +11,7 @@ exports_files([
|
|||||||
# This ensures that package.json in subdirectories get installed as well.
|
# This ensures that package.json in subdirectories get installed as well.
|
||||||
alias(
|
alias(
|
||||||
name = "install",
|
name = "install",
|
||||||
actual = "@yarn//:yarn",
|
actual = "@nodejs//:yarn",
|
||||||
)
|
)
|
||||||
|
|
||||||
node_modules_filegroup(
|
node_modules_filegroup(
|
||||||
@ -44,14 +44,16 @@ filegroup(
|
|||||||
"//:node_modules/zone.js/dist/zone.js",
|
"//:node_modules/zone.js/dist/zone.js",
|
||||||
"//:node_modules/zone.js/dist/zone-testing.js",
|
"//:node_modules/zone.js/dist/zone-testing.js",
|
||||||
"//:node_modules/zone.js/dist/task-tracking.js",
|
"//:node_modules/zone.js/dist/task-tracking.js",
|
||||||
|
"//:test-events.js",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
name = "angularjs",
|
name = "angularjs_scripts",
|
||||||
# do not sort
|
|
||||||
srcs = [
|
srcs = [
|
||||||
"//:node_modules/angular/angular.js",
|
"//:node_modules/angular-1.5/angular.js",
|
||||||
|
"//:node_modules/angular-mocks-1.5/angular-mocks.js",
|
||||||
"//:node_modules/angular-mocks/angular-mocks.js",
|
"//:node_modules/angular-mocks/angular-mocks.js",
|
||||||
|
"//:node_modules/angular/angular.js",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
93
CHANGELOG.md
93
CHANGELOG.md
@ -1,3 +1,96 @@
|
|||||||
|
<a name="6.0.8"></a>
|
||||||
|
## [6.0.8](https://github.com/angular/angular/compare/6.0.7...6.0.8) (2018-07-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **common:** do not round factional seconds ([#24831](https://github.com/angular/angular/issues/24831)) ([0746485](https://github.com/angular/angular/commit/0746485)), closes [#24384](https://github.com/angular/angular/issues/24384)
|
||||||
|
* **common:** properly update collection reference in NgForOf ([#24684](https://github.com/angular/angular/issues/24684)) ([9a98de9](https://github.com/angular/angular/commit/9a98de9)), closes [#24155](https://github.com/angular/angular/issues/24155)
|
||||||
|
* **common:** use correct currency format for locale de-AT ([#24658](https://github.com/angular/angular/issues/24658)) ([a92f111](https://github.com/angular/angular/commit/a92f111)), closes [#24609](https://github.com/angular/angular/issues/24609)
|
||||||
|
* **compiler-cli:** Use typescript to resolve modules for metadata ([#22856](https://github.com/angular/angular/issues/22856)) ([7717ff1](https://github.com/angular/angular/commit/7717ff1))
|
||||||
|
* **core:** use addCustomEqualityTester instead of overriding toEqual ([#22983](https://github.com/angular/angular/issues/22983)) ([b8975a9](https://github.com/angular/angular/commit/b8975a9)), closes [#22939](https://github.com/angular/angular/issues/22939)
|
||||||
|
* **language-service:** do not overwrite native `Reflect` ([#24299](https://github.com/angular/angular/issues/24299)) ([de1c44f](https://github.com/angular/angular/commit/de1c44f)), closes [#21420](https://github.com/angular/angular/issues/21420)
|
||||||
|
* **router:** add ability to recover from malformed url ([#23283](https://github.com/angular/angular/issues/23283)) ([2d4f4b5](https://github.com/angular/angular/commit/2d4f4b5)), closes [#21468](https://github.com/angular/angular/issues/21468)
|
||||||
|
* **service-worker:** avoid network requests when looking up hashed resources in cache ([#24127](https://github.com/angular/angular/issues/24127)) ([183b079](https://github.com/angular/angular/commit/183b079))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **core:** add support for ShadowDOM v1 ([#24718](https://github.com/angular/angular/issues/24718)) ([6c55a13](https://github.com/angular/angular/commit/6c55a13))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="6.0.7"></a>
|
||||||
|
## [6.0.7](https://github.com/angular/angular/compare/6.0.6...6.0.7) (2018-06-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **animations:** set animations styles properly on platform-server ([#24624](https://github.com/angular/angular/issues/24624)) ([0b356d4](https://github.com/angular/angular/commit/0b356d4))
|
||||||
|
* **common:** use correct ICU plural for locale mk ([#24659](https://github.com/angular/angular/issues/24659)) ([64a8584](https://github.com/angular/angular/commit/64a8584))
|
||||||
|
|
||||||
|
|
||||||
|
<a name="6.0.6"></a>
|
||||||
|
## [6.0.6](https://github.com/angular/angular/compare/6.0.5...6.0.6) (2018-06-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** support `.` in import statements. ([#20634](https://github.com/angular/angular/issues/20634)) ([e543c73](https://github.com/angular/angular/commit/e543c73)), closes [#20363](https://github.com/angular/angular/issues/20363)
|
||||||
|
* **core:** Injector correctly honors the @Self flag ([#24520](https://github.com/angular/angular/issues/24520)) ([f5b3661](https://github.com/angular/angular/commit/f5b3661))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="6.0.5"></a>
|
||||||
|
## [6.0.5](https://github.com/angular/angular/compare/6.0.4...6.0.5) (2018-06-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **animations:** always render end-state styles for orphaned DOM nodes ([#24236](https://github.com/angular/angular/issues/24236)) ([0139173](https://github.com/angular/angular/commit/0139173))
|
||||||
|
* **bazel:** Allow ng_module to depend on targets w no deps ([#24446](https://github.com/angular/angular/issues/24446)) ([ea3669e](https://github.com/angular/angular/commit/ea3669e))
|
||||||
|
* **docs-infra:** use script nomodule to load IE polyfills, skip other polyfills ([#24317](https://github.com/angular/angular/issues/24317)) ([e876535](https://github.com/angular/angular/commit/e876535)), closes [#23647](https://github.com/angular/angular/issues/23647)
|
||||||
|
* **router:** fix lazy loading of aux routes ([#23459](https://github.com/angular/angular/issues/23459)) ([d20877b](https://github.com/angular/angular/commit/d20877b)), closes [#10981](https://github.com/angular/angular/issues/10981)
|
||||||
|
* **service-worker:** fix `SwPush.unsubscribe()` ([#24162](https://github.com/angular/angular/issues/24162)) ([ea2987c](https://github.com/angular/angular/commit/ea2987c)), closes [#24095](https://github.com/angular/angular/issues/24095)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="6.0.4"></a>
|
||||||
|
## [6.0.4](https://github.com/angular/angular/compare/6.0.3...6.0.4) (2018-06-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **animations:** Fix browser detection logic ([#24188](https://github.com/angular/angular/issues/24188)) ([c9eb491](https://github.com/angular/angular/commit/c9eb491))
|
||||||
|
* **animations:** retain trigger-state for nodes that are moved around ([#24238](https://github.com/angular/angular/issues/24238)) ([19deca1](https://github.com/angular/angular/commit/19deca1))
|
||||||
|
* **forms:** properly handle special properties in FormGroup.get ([#22249](https://github.com/angular/angular/issues/22249)) ([dc3e8aa](https://github.com/angular/angular/commit/dc3e8aa)), closes [#17195](https://github.com/angular/angular/issues/17195)
|
||||||
|
* **platform-server:** avoid clash between server and client style encapsulation attributes ([#24158](https://github.com/angular/angular/issues/24158)) ([e9f2203](https://github.com/angular/angular/commit/e9f2203))
|
||||||
|
* **platform-server:** avoid dependency cycle when using http interceptor ([#24229](https://github.com/angular/angular/issues/24229)) ([2991b1b](https://github.com/angular/angular/commit/2991b1b)), closes [#23023](https://github.com/angular/angular/issues/23023)
|
||||||
|
* **platform-server:** don't reflect innerHTML property to attibute ([#24213](https://github.com/angular/angular/issues/24213)) ([c17098d](https://github.com/angular/angular/commit/c17098d)), closes [#19278](https://github.com/angular/angular/issues/19278)
|
||||||
|
* **platform-server:** provide Domino DOM types globally ([#24116](https://github.com/angular/angular/issues/24116)) ([906b3ec](https://github.com/angular/angular/commit/906b3ec)), closes [#23280](https://github.com/angular/angular/issues/23280) [#23133](https://github.com/angular/angular/issues/23133)
|
||||||
|
|
||||||
|
|
||||||
|
<a name="6.0.3"></a>
|
||||||
|
## [6.0.3](https://github.com/angular/angular/compare/6.0.2...6.0.3) (2018-05-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **service-worker:** check platformBrowser before accessing navigator.serviceWorker ([#21231](https://github.com/angular/angular/issues/21231)) ([0ee5b7e](https://github.com/angular/angular/commit/0ee5b7e))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="6.0.2"></a>
|
||||||
|
## [6.0.2](https://github.com/angular/angular/compare/6.0.1...6.0.2) (2018-05-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **animations:** do not throw errors when a destroyed component is animated ([#23836](https://github.com/angular/angular/issues/23836)) ([752b83a](https://github.com/angular/angular/commit/752b83a))
|
||||||
|
* **service-worker:** deprecate `versionedFiles` in asset-group resources ([#23584](https://github.com/angular/angular/issues/23584)) ([c6b618d](https://github.com/angular/angular/commit/c6b618d))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="6.0.1"></a>
|
<a name="6.0.1"></a>
|
||||||
# [6.0.1](https://github.com/angular/angular/compare/6.0.0...6.0.1) (2018-05-11)
|
# [6.0.1](https://github.com/angular/angular/compare/6.0.0...6.0.1) (2018-05-11)
|
||||||
|
|
||||||
|
@ -227,10 +227,15 @@ The following is the list of supported scopes:
|
|||||||
|
|
||||||
There are currently a few exceptions to the "use package name" rule:
|
There are currently a few exceptions to the "use package name" rule:
|
||||||
|
|
||||||
* **packaging**: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.
|
* **packaging**: used for changes that change the npm package layout in all of our packages, e.g.
|
||||||
|
public path changes, package.json changes done to all packages, d.ts file/format changes, changes
|
||||||
|
to bundles, etc.
|
||||||
* **changelog**: used for updating the release notes in CHANGELOG.md
|
* **changelog**: used for updating the release notes in CHANGELOG.md
|
||||||
* **aio**: used for docs-app (angular.io) related changes within the /aio directory of the repo
|
* **docs-infra**: used for docs-app (angular.io) related changes within the /aio directory of the
|
||||||
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`)
|
repo
|
||||||
|
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all
|
||||||
|
packages (e.g. `style: add missing semicolons`) and for docs changes that are not related to a
|
||||||
|
specific package (e.g. `docs: fix typo in tutorial`).
|
||||||
|
|
||||||
### Subject
|
### Subject
|
||||||
The subject contains a succinct description of the change:
|
The subject contains a succinct description of the change:
|
||||||
|
30
WORKSPACE
30
WORKSPACE
@ -6,23 +6,23 @@ workspace(name = "angular")
|
|||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "build_bazel_rules_nodejs",
|
name = "build_bazel_rules_nodejs",
|
||||||
url = "https://github.com/bazelbuild/rules_nodejs/archive/0.8.0.zip",
|
url = "https://github.com/bazelbuild/rules_nodejs/archive/0.10.1.zip",
|
||||||
strip_prefix = "rules_nodejs-0.8.0",
|
strip_prefix = "rules_nodejs-0.10.1",
|
||||||
sha256 = "4e40dd49ae7668d245c3107645f2a138660fcfd975b9310b91eda13f0c973953",
|
sha256 = "634206524d90dc03c52392fa3f19a16637d2bcf154910436fe1d669a0d9d7b9c",
|
||||||
)
|
)
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "io_bazel_rules_webtesting",
|
name = "io_bazel_rules_webtesting",
|
||||||
url = "https://github.com/bazelbuild/rules_webtesting/archive/ca7b8062d9cf4ef2fde9193c7d37a0764c4262d7.zip",
|
url = "https://github.com/bazelbuild/rules_webtesting/archive/v0.2.0.zip",
|
||||||
strip_prefix = "rules_webtesting-ca7b8062d9cf4ef2fde9193c7d37a0764c4262d7",
|
strip_prefix = "rules_webtesting-0.2.0",
|
||||||
sha256 = "28c73cf9d310fa6dba30e66bdb98071341c99c3feb8662f2d3883a632de97d72",
|
sha256 = "cecc12f07e95740750a40d38e8b14b76fefa1551bef9332cb432d564d693723c",
|
||||||
)
|
)
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "build_bazel_rules_typescript",
|
name = "build_bazel_rules_typescript",
|
||||||
url = "https://github.com/bazelbuild/rules_typescript/archive/v0.13.0.zip",
|
url = "https://github.com/bazelbuild/rules_typescript/archive/0.15.0.zip",
|
||||||
strip_prefix = "rules_typescript-0.13.0",
|
strip_prefix = "rules_typescript-0.15.0",
|
||||||
sha256 = "8f2767ff56ad68c80c62e9a1cdc2ba2c2ba0b19d350f713365e5333045df02e3",
|
sha256 = "1aa75917330b820cb239b3c10a936a10f0a46fe215063d4492dd76dc6e1616f4",
|
||||||
)
|
)
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
@ -34,13 +34,13 @@ http_archive(
|
|||||||
# This commit matches the version of buildifier in angular/ngcontainer
|
# This commit matches the version of buildifier in angular/ngcontainer
|
||||||
# If you change this, also check if it matches the version in the angular/ngcontainer
|
# If you change this, also check if it matches the version in the angular/ngcontainer
|
||||||
# version in /.circleci/config.yml
|
# version in /.circleci/config.yml
|
||||||
BAZEL_BUILDTOOLS_VERSION = "fd9878fd5de921e0bbab3dcdcb932c2627812ee1"
|
BAZEL_BUILDTOOLS_VERSION = "82b21607e00913b16fe1c51bec80232d9d6de31c"
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "com_github_bazelbuild_buildtools",
|
name = "com_github_bazelbuild_buildtools",
|
||||||
url = "https://github.com/bazelbuild/buildtools/archive/%s.zip" % BAZEL_BUILDTOOLS_VERSION,
|
url = "https://github.com/bazelbuild/buildtools/archive/%s.zip" % BAZEL_BUILDTOOLS_VERSION,
|
||||||
strip_prefix = "buildtools-%s" % BAZEL_BUILDTOOLS_VERSION,
|
strip_prefix = "buildtools-%s" % BAZEL_BUILDTOOLS_VERSION,
|
||||||
sha256 = "27bb461ade23fd44ba98723ad98f84ee9c83cd3540b773b186a1bc5037f3d862",
|
sha256 = "edb24c2f9c55b10a820ec74db0564415c0cf553fa55e9fc709a6332fb6685eff",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Fetching the Bazel source code allows us to compile the Skylark linter
|
# Fetching the Bazel source code allows us to compile the Skylark linter
|
||||||
@ -66,9 +66,9 @@ http_archive(
|
|||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "org_brotli",
|
name = "org_brotli",
|
||||||
url = "https://github.com/google/brotli/archive/c6333e1e79fb62ea088443f192293f964409b04e.zip",
|
url = "https://github.com/google/brotli/archive/f9b8c02673c576a3e807edbf3a9328e9e7af6d7c.zip",
|
||||||
strip_prefix = "brotli-c6333e1e79fb62ea088443f192293f964409b04e",
|
strip_prefix = "brotli-f9b8c02673c576a3e807edbf3a9328e9e7af6d7c",
|
||||||
sha256 = "3f781988dee7dd3bcce2bf238294663cfaaf3b6433505bdb762e24d0a284d1dc",
|
sha256 = "8a517806d2b7c8505ba5c53934e7d7c70d341b68ffd268e9044d35b564a48828",
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -77,7 +77,7 @@ http_archive(
|
|||||||
|
|
||||||
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install")
|
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install")
|
||||||
|
|
||||||
check_bazel_version("0.13.0")
|
check_bazel_version("0.14.0")
|
||||||
node_repositories(package_json = ["//:package.json"])
|
node_repositories(package_json = ["//:package.json"])
|
||||||
|
|
||||||
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
|
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
|
||||||
|
@ -52,8 +52,7 @@ export class BuildCleaner {
|
|||||||
protected removeDir(dir: string) {
|
protected removeDir(dir: string) {
|
||||||
try {
|
try {
|
||||||
if (shell.test('-d', dir)) {
|
if (shell.test('-d', dir)) {
|
||||||
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
|
shell.chmod('-R', 'a+w', dir);
|
||||||
(shell as any).chmod('-R', 'a+w', dir);
|
|
||||||
shell.rm('-rf', dir);
|
shell.rm('-rf', dir);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -106,8 +106,7 @@ export class BuildCreator extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
|
shell.chmod('-R', 'a-w', outputDir);
|
||||||
(shell as any).chmod('-R', 'a-w', outputDir);
|
|
||||||
shell.rm('-f', inputFile);
|
shell.rm('-f', inputFile);
|
||||||
resolve();
|
resolve();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -98,8 +98,7 @@ class Helper {
|
|||||||
const prDir = this.getPrDir(pr, isPublic);
|
const prDir = this.getPrDir(pr, isPublic);
|
||||||
|
|
||||||
if (fs.existsSync(prDir)) {
|
if (fs.existsSync(prDir)) {
|
||||||
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
|
shell.chmod('-R', 'a+w', prDir);
|
||||||
(shell as any).chmod('-R', 'a+w', prDir);
|
|
||||||
shell.rm('-rf', prDir);
|
shell.rm('-rf', prDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "yarn clean-dist",
|
"prebuild": "yarn clean-dist",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"build-watch": "yarn tsc --watch",
|
"build-watch": "yarn build --watch",
|
||||||
"clean-dist": "node --eval \"require('shelljs').rm('-rf', 'dist')\"",
|
"clean-dist": "node --eval \"require('shelljs').rm('-rf', 'dist')\"",
|
||||||
"dev": "concurrently --kill-others --raw --success first \"yarn build-watch\" \"yarn test-watch\"",
|
"dev": "concurrently --kill-others --raw --success first \"yarn build-watch\" \"yarn test-watch\"",
|
||||||
"lint": "tslint --project tsconfig.json",
|
"lint": "tslint --project tsconfig.json",
|
||||||
@ -33,7 +33,7 @@
|
|||||||
"@types/jasmine": "^2.6.0",
|
"@types/jasmine": "^2.6.0",
|
||||||
"@types/jsonwebtoken": "^7.2.3",
|
"@types/jsonwebtoken": "^7.2.3",
|
||||||
"@types/node": "^8.0.30",
|
"@types/node": "^8.0.30",
|
||||||
"@types/shelljs": "^0.7.4",
|
"@types/shelljs": "^0.8.0",
|
||||||
"@types/supertest": "^2.0.3",
|
"@types/supertest": "^2.0.3",
|
||||||
"concurrently": "^3.5.0",
|
"concurrently": "^3.5.0",
|
||||||
"nodemon": "^1.12.1",
|
"nodemon": "^1.12.1",
|
||||||
|
@ -69,9 +69,9 @@
|
|||||||
"@types/express-serve-static-core" "*"
|
"@types/express-serve-static-core" "*"
|
||||||
"@types/mime" "*"
|
"@types/mime" "*"
|
||||||
|
|
||||||
"@types/shelljs@^0.7.4":
|
"@types/shelljs@^0.8.0":
|
||||||
version "0.7.4"
|
version "0.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.7.4.tgz#137b5f31306eaff4de120ffe5b9d74b297809cfc"
|
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.0.tgz#0caa56b68baae4f68f44e0dd666ab30b098e3632"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/glob" "*"
|
"@types/glob" "*"
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
set -eux -o pipefail
|
set -eux -o pipefail
|
||||||
exec 3>&1
|
exec 3>&1
|
||||||
|
|
||||||
echo "\n\n[`date`] - Updating the preview server..."
|
echo -e "\n\n[`date`] - Updating the preview server..."
|
||||||
|
|
||||||
# Input
|
# Input
|
||||||
readonly HOST_REPO_DIR=$1
|
readonly HOST_REPO_DIR=$1
|
||||||
|
2
aio/content/examples/.gitignore
vendored
2
aio/content/examples/.gitignore
vendored
@ -60,6 +60,8 @@ dist/
|
|||||||
!rollup-config.js
|
!rollup-config.js
|
||||||
aot-compiler/**/*.d.ts
|
aot-compiler/**/*.d.ts
|
||||||
aot-compiler/**/*.factory.d.ts
|
aot-compiler/**/*.factory.d.ts
|
||||||
|
upgrade-phonecat-2-hybrid/aot/**/*
|
||||||
|
!upgrade-phonecat-2-hybrid/aot/index.html
|
||||||
|
|
||||||
# i18n
|
# i18n
|
||||||
!i18n/src/systemjs-text-plugin.js
|
!i18n/src/systemjs-text-plugin.js
|
||||||
|
@ -40,5 +40,7 @@ export class HighlightDirective {
|
|||||||
// #docregion color-2
|
// #docregion color-2
|
||||||
@Input() appHighlight: string;
|
@Input() appHighlight: string;
|
||||||
// #enddocregion color-2
|
// #enddocregion color-2
|
||||||
}
|
|
||||||
|
|
||||||
|
// #docregion
|
||||||
|
}
|
||||||
|
// #enddocregion
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
# MasterProject
|
|
||||||
|
|
||||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.0.0-rc.0.
|
|
||||||
|
|
||||||
## Development server
|
|
||||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
|
||||||
|
|
||||||
## Code scaffolding
|
|
||||||
|
|
||||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`.
|
|
||||||
|
|
||||||
## Build
|
|
||||||
|
|
||||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
|
|
||||||
|
|
||||||
## Running unit tests
|
|
||||||
|
|
||||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
|
||||||
|
|
||||||
## Running end-to-end tests
|
|
||||||
|
|
||||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
|
||||||
Before running the tests make sure you are serving the app via `ng serve`.
|
|
||||||
|
|
||||||
## Further help
|
|
||||||
|
|
||||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
|
@ -5,18 +5,18 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
|
|||||||
selector: 'app-voter',
|
selector: 'app-voter',
|
||||||
template: `
|
template: `
|
||||||
<h4>{{name}}</h4>
|
<h4>{{name}}</h4>
|
||||||
<button (click)="vote(true)" [disabled]="voted">Agree</button>
|
<button (click)="vote(true)" [disabled]="didVote">Agree</button>
|
||||||
<button (click)="vote(false)" [disabled]="voted">Disagree</button>
|
<button (click)="vote(false)" [disabled]="didVote">Disagree</button>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class VoterComponent {
|
export class VoterComponent {
|
||||||
@Input() name: string;
|
@Input() name: string;
|
||||||
@Output() onVoted = new EventEmitter<boolean>();
|
@Output() voted = new EventEmitter<boolean>();
|
||||||
voted = false;
|
didVote = false;
|
||||||
|
|
||||||
vote(agreed: boolean) {
|
vote(agreed: boolean) {
|
||||||
this.onVoted.emit(agreed);
|
this.voted.emit(agreed);
|
||||||
this.voted = true;
|
this.didVote = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
@ -8,7 +8,7 @@ import { Component } from '@angular/core';
|
|||||||
<h3>Agree: {{agreed}}, Disagree: {{disagreed}}</h3>
|
<h3>Agree: {{agreed}}, Disagree: {{disagreed}}</h3>
|
||||||
<app-voter *ngFor="let voter of voters"
|
<app-voter *ngFor="let voter of voters"
|
||||||
[name]="voter"
|
[name]="voter"
|
||||||
(onVoted)="onVoted($event)">
|
(voted)="onVoted($event)">
|
||||||
</app-voter>
|
</app-voter>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
|
@ -16,6 +16,7 @@ describe('Form Validation Tests', function () {
|
|||||||
|
|
||||||
tests('Template-Driven Form');
|
tests('Template-Driven Form');
|
||||||
bobTests();
|
bobTests();
|
||||||
|
crossValidationTests();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Reactive form', () => {
|
describe('Reactive form', () => {
|
||||||
@ -25,6 +26,7 @@ describe('Form Validation Tests', function () {
|
|||||||
|
|
||||||
tests('Reactive Form');
|
tests('Reactive Form');
|
||||||
bobTests();
|
bobTests();
|
||||||
|
crossValidationTests();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -42,7 +44,8 @@ let page: {
|
|||||||
powerOption: ElementFinder,
|
powerOption: ElementFinder,
|
||||||
errorMessages: ElementArrayFinder,
|
errorMessages: ElementArrayFinder,
|
||||||
heroFormButtons: ElementArrayFinder,
|
heroFormButtons: ElementArrayFinder,
|
||||||
heroSubmitted: ElementFinder
|
heroSubmitted: ElementFinder,
|
||||||
|
crossValidationErrorMessage: ElementFinder,
|
||||||
};
|
};
|
||||||
|
|
||||||
function getPage(sectionTag: string) {
|
function getPage(sectionTag: string) {
|
||||||
@ -59,7 +62,8 @@ function getPage(sectionTag: string) {
|
|||||||
powerOption: section.element(by.css('#power option')),
|
powerOption: section.element(by.css('#power option')),
|
||||||
errorMessages: section.all(by.css('div.alert')),
|
errorMessages: section.all(by.css('div.alert')),
|
||||||
heroFormButtons: buttons,
|
heroFormButtons: buttons,
|
||||||
heroSubmitted: section.element(by.css('.submitted-message'))
|
heroSubmitted: section.element(by.css('.submitted-message')),
|
||||||
|
crossValidationErrorMessage: section.element(by.css('.cross-validation-error-message')),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,3 +176,29 @@ function bobTests() {
|
|||||||
expectFormIsValid();
|
expectFormIsValid();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function crossValidationTests() {
|
||||||
|
const emsg = 'Name cannot match alter ego.';
|
||||||
|
|
||||||
|
it(`should produce "${emsg}" error after setting name and alter ego to the same value`, function () {
|
||||||
|
page.nameInput.clear();
|
||||||
|
page.nameInput.sendKeys('Batman');
|
||||||
|
|
||||||
|
page.alterEgoInput.clear();
|
||||||
|
page.alterEgoInput.sendKeys('Batman');
|
||||||
|
|
||||||
|
expectFormIsInvalid();
|
||||||
|
expect(page.crossValidationErrorMessage.getText()).toBe(emsg);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be ok again with different values', function () {
|
||||||
|
page.nameInput.clear();
|
||||||
|
page.nameInput.sendKeys('Batman');
|
||||||
|
|
||||||
|
page.alterEgoInput.clear();
|
||||||
|
page.alterEgoInput.sendKeys('Superman');
|
||||||
|
|
||||||
|
expectFormIsValid();
|
||||||
|
expect(page.crossValidationErrorMessage.isPresent()).toBe(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -7,7 +7,7 @@ import { AppComponent } from './app.component';
|
|||||||
import { HeroFormTemplateComponent } from './template/hero-form-template.component';
|
import { HeroFormTemplateComponent } from './template/hero-form-template.component';
|
||||||
import { HeroFormReactiveComponent } from './reactive/hero-form-reactive.component';
|
import { HeroFormReactiveComponent } from './reactive/hero-form-reactive.component';
|
||||||
import { ForbiddenValidatorDirective } from './shared/forbidden-name.directive';
|
import { ForbiddenValidatorDirective } from './shared/forbidden-name.directive';
|
||||||
|
import { IdentityRevealedValidatorDirective } from './shared/identity-revealed.directive';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -19,7 +19,8 @@ import { ForbiddenValidatorDirective } from './shared/forbidden-name.directive';
|
|||||||
AppComponent,
|
AppComponent,
|
||||||
HeroFormTemplateComponent,
|
HeroFormTemplateComponent,
|
||||||
HeroFormReactiveComponent,
|
HeroFormReactiveComponent,
|
||||||
ForbiddenValidatorDirective
|
ForbiddenValidatorDirective,
|
||||||
|
IdentityRevealedValidatorDirective
|
||||||
],
|
],
|
||||||
bootstrap: [ AppComponent ]
|
bootstrap: [ AppComponent ]
|
||||||
})
|
})
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/* tslint:disable: member-ordering forin */
|
||||||
|
// #docplaster
|
||||||
|
// #docregion
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { forbiddenNameValidator } from '../shared/forbidden-name.directive';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-hero-form-reactive',
|
||||||
|
templateUrl: './hero-form-reactive.component.html',
|
||||||
|
styleUrls: ['./hero-form-reactive.component.css'],
|
||||||
|
})
|
||||||
|
export class HeroFormReactiveComponent implements OnInit {
|
||||||
|
|
||||||
|
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
|
||||||
|
|
||||||
|
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
|
||||||
|
|
||||||
|
heroForm: FormGroup;
|
||||||
|
|
||||||
|
// #docregion form-group
|
||||||
|
ngOnInit(): void {
|
||||||
|
// #docregion custom-validator
|
||||||
|
this.heroForm = new FormGroup({
|
||||||
|
'name': new FormControl(this.hero.name, [
|
||||||
|
Validators.required,
|
||||||
|
Validators.minLength(4),
|
||||||
|
forbiddenNameValidator(/bob/i) // <-- Here's how you pass in the custom validator.
|
||||||
|
]),
|
||||||
|
'alterEgo': new FormControl(this.hero.alterEgo),
|
||||||
|
'power': new FormControl(this.hero.power, Validators.required)
|
||||||
|
});
|
||||||
|
// #enddocregion custom-validator
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() { return this.heroForm.get('name'); }
|
||||||
|
|
||||||
|
get power() { return this.heroForm.get('power'); }
|
||||||
|
// #enddocregion form-group
|
||||||
|
}
|
||||||
|
// #enddocregion
|
@ -0,0 +1,5 @@
|
|||||||
|
/* #docregion cross-validation-error-css */
|
||||||
|
.cross-validation-error input {
|
||||||
|
border-left: 5px solid red;
|
||||||
|
}
|
||||||
|
/* #enddocregion cross-validation-error-css */
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
<div [hidden]="formDir.submitted">
|
<div [hidden]="formDir.submitted">
|
||||||
|
|
||||||
|
<div class="cross-validation" [class.cross-validation-error]="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
@ -36,6 +37,13 @@
|
|||||||
formControlName="alterEgo" >
|
formControlName="alterEgo" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- #docregion cross-validation-error-message -->
|
||||||
|
<div *ngIf="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)" class="cross-validation-error-message alert alert-danger">
|
||||||
|
Name cannot match alter ego.
|
||||||
|
</div>
|
||||||
|
<!-- #enddocregion cross-validation-error-message -->
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="power">Hero Power</label>
|
<label for="power">Hero Power</label>
|
||||||
<select id="power" class="form-control"
|
<select id="power" class="form-control"
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
/* tslint:disable: member-ordering forin */
|
/* tslint:disable: member-ordering forin */
|
||||||
// #docplaster
|
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||||
import { forbiddenNameValidator } from '../shared/forbidden-name.directive';
|
import { forbiddenNameValidator } from '../shared/forbidden-name.directive';
|
||||||
|
import { identityRevealedValidator } from '../shared/identity-revealed.directive';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hero-form-reactive',
|
selector: 'app-hero-form-reactive',
|
||||||
templateUrl: './hero-form-reactive.component.html'
|
templateUrl: './hero-form-reactive.component.html',
|
||||||
|
styleUrls: ['./hero-form-reactive.component.css'],
|
||||||
})
|
})
|
||||||
export class HeroFormReactiveComponent implements OnInit {
|
export class HeroFormReactiveComponent implements OnInit {
|
||||||
|
|
||||||
@ -17,24 +18,19 @@ export class HeroFormReactiveComponent implements OnInit {
|
|||||||
|
|
||||||
heroForm: FormGroup;
|
heroForm: FormGroup;
|
||||||
|
|
||||||
// #docregion form-group
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
// #docregion custom-validator
|
|
||||||
this.heroForm = new FormGroup({
|
this.heroForm = new FormGroup({
|
||||||
'name': new FormControl(this.hero.name, [
|
'name': new FormControl(this.hero.name, [
|
||||||
Validators.required,
|
Validators.required,
|
||||||
Validators.minLength(4),
|
Validators.minLength(4),
|
||||||
forbiddenNameValidator(/bob/i) // <-- Here's how you pass in the custom validator.
|
forbiddenNameValidator(/bob/i)
|
||||||
]),
|
]),
|
||||||
'alterEgo': new FormControl(this.hero.alterEgo),
|
'alterEgo': new FormControl(this.hero.alterEgo),
|
||||||
'power': new FormControl(this.hero.power, Validators.required)
|
'power': new FormControl(this.hero.power, Validators.required)
|
||||||
});
|
}, { validators: identityRevealedValidator }); // <-- add custom validator at the FormGroup level
|
||||||
// #enddocregion custom-validator
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get name() { return this.heroForm.get('name'); }
|
get name() { return this.heroForm.get('name'); }
|
||||||
|
|
||||||
get power() { return this.heroForm.get('power'); }
|
get power() { return this.heroForm.get('power'); }
|
||||||
// #enddocregion form-group
|
|
||||||
}
|
}
|
||||||
// #enddocregion
|
|
||||||
|
@ -5,7 +5,7 @@ import { AbstractControl, NG_VALIDATORS, Validator, ValidatorFn, Validators } fr
|
|||||||
// #docregion custom-validator
|
// #docregion custom-validator
|
||||||
/** A hero's name can't match the given regular expression */
|
/** A hero's name can't match the given regular expression */
|
||||||
export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
|
export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
|
||||||
return (control: AbstractControl): {[key: string]: any} => {
|
return (control: AbstractControl): {[key: string]: any} | null => {
|
||||||
const forbidden = nameRe.test(control.value);
|
const forbidden = nameRe.test(control.value);
|
||||||
return forbidden ? {'forbiddenName': {value: control.value}} : null;
|
return forbidden ? {'forbiddenName': {value: control.value}} : null;
|
||||||
};
|
};
|
||||||
@ -22,7 +22,7 @@ export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
|
|||||||
export class ForbiddenValidatorDirective implements Validator {
|
export class ForbiddenValidatorDirective implements Validator {
|
||||||
@Input('appForbiddenName') forbiddenName: string;
|
@Input('appForbiddenName') forbiddenName: string;
|
||||||
|
|
||||||
validate(control: AbstractControl): {[key: string]: any} {
|
validate(control: AbstractControl): {[key: string]: any} | null {
|
||||||
return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control)
|
return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
// #docregion
|
||||||
|
import { Directive } from '@angular/core';
|
||||||
|
import { AbstractControl, FormGroup, NG_VALIDATORS, ValidationErrors, Validator, ValidatorFn } from '@angular/forms';
|
||||||
|
|
||||||
|
// #docregion cross-validation-validator
|
||||||
|
/** A hero's name can't match the hero's alter ego */
|
||||||
|
export const identityRevealedValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
|
||||||
|
const name = control.get('name');
|
||||||
|
const alterEgo = control.get('alterEgo');
|
||||||
|
|
||||||
|
return name && alterEgo && name.value === alterEgo.value ? { 'identityRevealed': true } : null;
|
||||||
|
};
|
||||||
|
// #enddocregion cross-validation-validator
|
||||||
|
|
||||||
|
// #docregion cross-validation-directive
|
||||||
|
@Directive({
|
||||||
|
selector: '[appIdentityRevealed]',
|
||||||
|
providers: [{ provide: NG_VALIDATORS, useExisting: IdentityRevealedValidatorDirective, multi: true }]
|
||||||
|
})
|
||||||
|
export class IdentityRevealedValidatorDirective implements Validator {
|
||||||
|
validate(control: AbstractControl): ValidationErrors {
|
||||||
|
return identityRevealedValidator(control)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #enddocregion cross-validation-directive
|
@ -0,0 +1,4 @@
|
|||||||
|
/* #docregion */
|
||||||
|
.cross-validation-error input {
|
||||||
|
border-left: 5px solid red;
|
||||||
|
}
|
@ -2,11 +2,11 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<h1>Template-Driven Form</h1>
|
<h1>Template-Driven Form</h1>
|
||||||
<!-- #docregion form-tag-->
|
<!-- #docregion cross-validation-register-validator -->
|
||||||
<form #heroForm="ngForm">
|
<form #heroForm="ngForm" appIdentityRevealed>
|
||||||
<!-- #enddocregion form-tag-->
|
<!-- #enddocregion cross-validation-register-validator -->
|
||||||
<div [hidden]="heroForm.submitted">
|
<div [hidden]="heroForm.submitted">
|
||||||
|
<div class="cross-validation" [class.cross-validation-error]="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
<!-- #docregion name-with-error-msg -->
|
<!-- #docregion name-with-error-msg -->
|
||||||
@ -39,6 +39,13 @@
|
|||||||
name="alterEgo" [(ngModel)]="hero.alterEgo" >
|
name="alterEgo" [(ngModel)]="hero.alterEgo" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- #docregion cross-validation-error-message -->
|
||||||
|
<div *ngIf="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)" class="cross-validation-error-message alert alert-danger">
|
||||||
|
Name cannot match alter ego.
|
||||||
|
</div>
|
||||||
|
<!-- #enddocregion cross-validation-error-message -->
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="power">Hero Power</label>
|
<label for="power">Hero Power</label>
|
||||||
<select id="power" name="power" class="form-control"
|
<select id="power" name="power" class="form-control"
|
||||||
@ -62,5 +69,4 @@
|
|||||||
<button (click)="heroForm.resetForm({})">Add new hero</button>
|
<button (click)="heroForm.resetForm({})">Add new hero</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,9 +3,11 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
// #docregion component
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hero-form-template',
|
selector: 'app-hero-form-template',
|
||||||
templateUrl: './hero-form-template.component.html'
|
templateUrl: './hero-form-template.component.html',
|
||||||
|
styleUrls: ['./hero-form-template.component.css'],
|
||||||
})
|
})
|
||||||
export class HeroFormTemplateComponent {
|
export class HeroFormTemplateComponent {
|
||||||
|
|
||||||
@ -14,3 +16,4 @@ export class HeroFormTemplateComponent {
|
|||||||
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
|
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// #enddocregion
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"description": "Validation",
|
"description": "Validation",
|
||||||
"files":[
|
"files":[
|
||||||
"!**/*.d.ts",
|
"!**/*.d.ts",
|
||||||
"!**/*.js"
|
"!**/*.js",
|
||||||
|
"!**/*.[1].*"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,8 @@ button {
|
|||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
code, .code {
|
code,
|
||||||
|
.code {
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
color: black;
|
color: black;
|
||||||
font-family: Courier, sans-serif;
|
font-family: Courier, sans-serif;
|
||||||
@ -21,14 +22,18 @@ div.code {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
margin: 40px 0
|
margin: 40px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
td, th {
|
td,
|
||||||
|
th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* #docregion p-span */
|
/* #docregion p-span */
|
||||||
p span { color: red; font-size: 70%; }
|
p span {
|
||||||
|
color: red;
|
||||||
|
font-size: 70%;
|
||||||
|
}
|
||||||
/* #enddocregion p-span */
|
/* #enddocregion p-span */
|
||||||
|
@ -132,7 +132,7 @@
|
|||||||
<!-- #docregion select-span -->
|
<!-- #docregion select-span -->
|
||||||
<select [(ngModel)]="hero">
|
<select [(ngModel)]="hero">
|
||||||
<span *ngFor="let h of heroes">
|
<span *ngFor="let h of heroes">
|
||||||
<span *ngIf="showSad || h?.emotion != 'sad'">
|
<span *ngIf="showSad || h?.emotion !== 'sad'">
|
||||||
<option [ngValue]="h">{{h.name}} ({{h?.emotion}})</option>
|
<option [ngValue]="h">{{h.name}} ({{h?.emotion}})</option>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
@ -147,7 +147,7 @@
|
|||||||
<!-- #docregion select-ngcontainer -->
|
<!-- #docregion select-ngcontainer -->
|
||||||
<select [(ngModel)]="hero">
|
<select [(ngModel)]="hero">
|
||||||
<ng-container *ngFor="let h of heroes">
|
<ng-container *ngFor="let h of heroes">
|
||||||
<ng-container *ngIf="showSad || h?.emotion != 'sad'">
|
<ng-container *ngIf="showSad || h?.emotion !== 'sad'">
|
||||||
<option [ngValue]="h">{{h.name}} ({{h?.emotion}})</option>
|
<option [ngValue]="h">{{h.name}} ({{h?.emotion}})</option>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@ -14,6 +14,7 @@ export class AppComponent {
|
|||||||
heroTraits = ['honest', 'brave', 'considerate'];
|
heroTraits = ['honest', 'brave', 'considerate'];
|
||||||
|
|
||||||
// flags for the table
|
// flags for the table
|
||||||
|
|
||||||
attrDirs = true;
|
attrDirs = true;
|
||||||
strucDirs = true;
|
strucDirs = true;
|
||||||
divNgIf = false;
|
divNgIf = false;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
import { Hero } from './hero';
|
import { Hero } from './hero';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -33,11 +34,15 @@ export class ConfusedHeroComponent {
|
|||||||
export class UnknownHeroComponent {
|
export class UnknownHeroComponent {
|
||||||
@Input() hero: Hero;
|
@Input() hero: Hero;
|
||||||
get message() {
|
get message() {
|
||||||
return this.hero && this.hero.name ?
|
return this.hero && this.hero.name
|
||||||
`${this.hero.name} is strange and mysterious.` :
|
? `${this.hero.name} is strange and mysterious.`
|
||||||
'Are you feeling indecisive?';
|
: 'Are you feeling indecisive?';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const heroComponents =
|
export const heroComponents = [
|
||||||
[ HappyHeroComponent, SadHeroComponent, ConfusedHeroComponent, UnknownHeroComponent ];
|
HappyHeroComponent,
|
||||||
|
SadHeroComponent,
|
||||||
|
ConfusedHeroComponent,
|
||||||
|
UnknownHeroComponent
|
||||||
|
];
|
||||||
|
@ -15,6 +15,7 @@ export class ComposeMessageComponent {
|
|||||||
@HostBinding('style.position') position = 'absolute';
|
@HostBinding('style.position') position = 'absolute';
|
||||||
|
|
||||||
details: string;
|
details: string;
|
||||||
|
message: string;
|
||||||
sending = false;
|
sending = false;
|
||||||
|
|
||||||
constructor(private router: Router) {}
|
constructor(private router: Router) {}
|
||||||
|
@ -7,12 +7,9 @@
|
|||||||
"resources": {
|
"resources": {
|
||||||
"files": [
|
"files": [
|
||||||
"/favicon.ico",
|
"/favicon.ico",
|
||||||
"/index.html"
|
"/index.html",
|
||||||
],
|
"/*.css",
|
||||||
"versionedFiles": [
|
"/*.js"
|
||||||
"/*.bundle.css",
|
|
||||||
"/*.bundle.js",
|
|
||||||
"/*.chunk.js"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
// Import spec files individually for Stackblitz
|
// Import spec files individually for Stackblitz
|
||||||
import 'app/about/about.component.spec.ts';
|
import './app/about/about.component.spec.ts';
|
||||||
import 'app/app-initial.component.spec.ts';
|
import './app/app-initial.component.spec.ts';
|
||||||
import 'app/app.component.router.spec.ts';
|
import './app/app.component.router.spec.ts';
|
||||||
import 'app/app.component.spec.ts';
|
import './app/app.component.spec.ts';
|
||||||
import 'app/banner/banner-initial.component.spec.ts';
|
import './app/banner/banner-initial.component.spec.ts';
|
||||||
import 'app/banner/banner.component.spec.ts';
|
import './app/banner/banner.component.spec.ts';
|
||||||
import 'app/banner/banner.component.detect-changes.spec.ts';
|
import './app/banner/banner.component.detect-changes.spec.ts';
|
||||||
import 'app/banner/banner-external.component.spec.ts';
|
import './app/banner/banner-external.component.spec.ts';
|
||||||
import 'app/dashboard/dashboard-hero.component.spec.ts';
|
import './app/dashboard/dashboard-hero.component.spec.ts';
|
||||||
import 'app/dashboard/dashboard.component.no-testbed.spec.ts';
|
import './app/dashboard/dashboard.component.no-testbed.spec.ts';
|
||||||
import 'app/dashboard/dashboard.component.spec.ts';
|
import './app/dashboard/dashboard.component.spec.ts';
|
||||||
import 'app/demo/async-helper.spec.ts';
|
import './app/demo/async-helper.spec.ts';
|
||||||
import 'app/demo/demo.spec.ts';
|
import './app/demo/demo.spec.ts';
|
||||||
import 'app/demo/demo.testbed.spec.ts';
|
import './app/demo/demo.testbed.spec.ts';
|
||||||
import 'app/hero/hero-detail.component.no-testbed.spec.ts';
|
import './app/hero/hero-detail.component.no-testbed.spec.ts';
|
||||||
import 'app/hero/hero-detail.component.spec.ts';
|
import './app/hero/hero-detail.component.spec.ts';
|
||||||
import 'app/hero/hero-list.component.spec.ts';
|
import './app/hero/hero-list.component.spec.ts';
|
||||||
import 'app/model/hero.service.spec.ts';
|
import './app/model/hero.service.spec.ts';
|
||||||
import 'app/model/http-hero.service.spec.ts';
|
import './app/model/http-hero.service.spec.ts';
|
||||||
import 'app/model/testing/http-client.spec.ts';
|
import './app/model/testing/http-client.spec.ts';
|
||||||
import 'app/shared/highlight.directive.spec.ts';
|
import './app/shared/highlight.directive.spec.ts';
|
||||||
import 'app/shared/title-case.pipe.spec.ts';
|
import './app/shared/title-case.pipe.spec.ts';
|
||||||
import 'app/twain/twain.component.spec.ts';
|
import './app/twain/twain.component.spec.ts';
|
||||||
import 'app/twain/twain.component.marbles.spec.ts';
|
import './app/twain/twain.component.marbles.spec.ts';
|
||||||
import 'app/welcome/welcome.component.spec.ts';
|
import './app/welcome/welcome.component.spec.ts';
|
||||||
|
@ -18,11 +18,11 @@ nav a {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
nav a:visited, a:link {
|
nav a:visited, a:link {
|
||||||
color: #607D8B;
|
color: #607d8b;
|
||||||
}
|
}
|
||||||
nav a:hover {
|
nav a:hover {
|
||||||
color: #039be5;
|
color: #039be5;
|
||||||
background-color: #CFD8DC;
|
background-color: #cfd8dc;
|
||||||
}
|
}
|
||||||
nav a.active {
|
nav a.active {
|
||||||
color: #039be5;
|
color: #039be5;
|
||||||
|
@ -33,11 +33,11 @@ h4 {
|
|||||||
color: #eee;
|
color: #eee;
|
||||||
max-height: 120px;
|
max-height: 120px;
|
||||||
min-width: 120px;
|
min-width: 120px;
|
||||||
background-color: #607D8B;
|
background-color: #607d8b;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
.module:hover {
|
.module:hover {
|
||||||
background-color: #EEE;
|
background-color: #eee;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #607d8b;
|
color: #607d8b;
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,36 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { DashboardComponent } from './dashboard.component';
|
import { DashboardComponent } from './dashboard.component';
|
||||||
|
import { HeroSearchComponent } from '../hero-search/hero-search.component';
|
||||||
|
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { HEROES } from '../mock-heroes';
|
||||||
|
import { HeroService } from '../hero.service';
|
||||||
|
|
||||||
describe('DashboardComponent', () => {
|
describe('DashboardComponent', () => {
|
||||||
let component: DashboardComponent;
|
let component: DashboardComponent;
|
||||||
let fixture: ComponentFixture<DashboardComponent>;
|
let fixture: ComponentFixture<DashboardComponent>;
|
||||||
|
let heroService;
|
||||||
|
let getHeroesSpy;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
|
heroService = jasmine.createSpyObj('HeroService', ['getHeroes']);
|
||||||
|
getHeroesSpy = heroService.getHeroes.and.returnValue( of(HEROES) );
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ DashboardComponent ]
|
declarations: [
|
||||||
|
DashboardComponent,
|
||||||
|
HeroSearchComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
RouterTestingModule.withRoutes([])
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: HeroService, useValue: heroService }
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -22,4 +42,17 @@ describe('DashboardComponent', () => {
|
|||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should display "Top Heroes" as headline', () => {
|
||||||
|
expect(fixture.nativeElement.querySelector('h3').textContent).toEqual('Top Heroes');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call heroService', async(() => {
|
||||||
|
expect(getHeroesSpy.calls.any()).toBe(true);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should display 4 links', async(() => {
|
||||||
|
expect(fixture.nativeElement.querySelectorAll('a').length).toEqual(4);
|
||||||
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||||
|
|
||||||
import { HeroSearchComponent } from './hero-search.component';
|
import { HeroSearchComponent } from './hero-search.component';
|
||||||
|
|
||||||
|
|
||||||
describe('HeroSearchComponent', () => {
|
describe('HeroSearchComponent', () => {
|
||||||
let component: HeroSearchComponent;
|
let component: HeroSearchComponent;
|
||||||
let fixture: ComponentFixture<HeroSearchComponent>;
|
let fixture: ComponentFixture<HeroSearchComponent>;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ HeroSearchComponent ]
|
declarations: [ HeroSearchComponent ],
|
||||||
|
imports: [RouterTestingModule.withRoutes([]), HttpClientTestingModule]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
@ -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(heroes => this.log('fetched heroes')),
|
||||||
// #docregion getHeroes-2
|
// #docregion getHeroes-2
|
||||||
catchError(this.handleError('getHeroes', []))
|
catchError(this.handleError('getHeroes', []))
|
||||||
);
|
);
|
||||||
@ -84,7 +84,7 @@ export class HeroService {
|
|||||||
// if not search term, return empty hero array.
|
// if not search term, return empty hero array.
|
||||||
return of([]);
|
return of([]);
|
||||||
}
|
}
|
||||||
return this.http.get<Hero[]>(`api/heroes/?name=${term}`).pipe(
|
return this.http.get<Hero[]>(`${this.heroesUrl}/?name=${term}`).pipe(
|
||||||
tap(_ => this.log(`found heroes matching "${term}"`)),
|
tap(_ => this.log(`found heroes matching "${term}"`)),
|
||||||
catchError(this.handleError<Hero[]>('searchHeroes', []))
|
catchError(this.handleError<Hero[]>('searchHeroes', []))
|
||||||
);
|
);
|
||||||
@ -151,7 +151,7 @@ export class HeroService {
|
|||||||
// #docregion log
|
// #docregion log
|
||||||
/** Log a HeroService message with the MessageService */
|
/** Log a HeroService message with the MessageService */
|
||||||
private log(message: string) {
|
private log(message: string) {
|
||||||
this.messageService.add('HeroService: ' + message);
|
this.messageService.add(`HeroService: ${message}`);
|
||||||
}
|
}
|
||||||
// #enddocregion log
|
// #enddocregion log
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { HeroesComponent } from './heroes.component';
|
import { HeroesComponent } from './heroes.component';
|
||||||
|
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||||
|
|
||||||
describe('HeroesComponent', () => {
|
describe('HeroesComponent', () => {
|
||||||
let component: HeroesComponent;
|
let component: HeroesComponent;
|
||||||
@ -8,7 +9,8 @@ describe('HeroesComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [ HeroesComponent ]
|
declarations: [ HeroesComponent ],
|
||||||
|
imports: [RouterTestingModule.withRoutes([]), HttpClientTestingModule],
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
@ -30,7 +30,7 @@ export class HeroService {
|
|||||||
getHeroes (): Observable<Hero[]> {
|
getHeroes (): Observable<Hero[]> {
|
||||||
return this.http.get<Hero[]>(this.heroesUrl)
|
return this.http.get<Hero[]>(this.heroesUrl)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap(heroes => this.log(`fetched heroes`)),
|
tap(heroes => this.log('fetched heroes')),
|
||||||
catchError(this.handleError('getHeroes', []))
|
catchError(this.handleError('getHeroes', []))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ export class HeroService {
|
|||||||
// if not search term, return empty hero array.
|
// if not search term, return empty hero array.
|
||||||
return of([]);
|
return of([]);
|
||||||
}
|
}
|
||||||
return this.http.get<Hero[]>(`api/heroes/?name=${term}`).pipe(
|
return this.http.get<Hero[]>(`${this.heroesUrl}/?name=${term}`).pipe(
|
||||||
tap(_ => this.log(`found heroes matching "${term}"`)),
|
tap(_ => this.log(`found heroes matching "${term}"`)),
|
||||||
catchError(this.handleError<Hero[]>('searchHeroes', []))
|
catchError(this.handleError<Hero[]>('searchHeroes', []))
|
||||||
);
|
);
|
||||||
@ -123,6 +123,6 @@ export class HeroService {
|
|||||||
|
|
||||||
/** Log a HeroService message with the MessageService */
|
/** Log a HeroService message with the MessageService */
|
||||||
private log(message: string) {
|
private log(message: string) {
|
||||||
this.messageService.add('HeroService: ' + message);
|
this.messageService.add(`HeroService: ${message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"removeComments": false,
|
"removeComments": false,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
|
"skipLibCheck": true,
|
||||||
"suppressImplicitAnyIndexErrors": true
|
"suppressImplicitAnyIndexErrors": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,8 @@
|
|||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"lib": [ "es2015", "dom" ],
|
"lib": [ "es2015", "dom" ],
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"suppressImplicitAnyIndexErrors": true,
|
"skipLibCheck": true,
|
||||||
"typeRoots": [
|
"suppressImplicitAnyIndexErrors": true
|
||||||
"./node_modules/@types/"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"compileOnSave": true,
|
"compileOnSave": true,
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { platformBrowser } from '@angular/platform-browser';
|
import { platformBrowser } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { AppModuleNgFactory } from '../aot/app/app.module.ngfactory';
|
import { AppModuleNgFactory } from './app.module.ngfactory';
|
||||||
|
|
||||||
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
|
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
// #enddocregion activatedroute
|
// #enddocregion activatedroute
|
||||||
import { Observable } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
|
|
||||||
import { async, TestBed } from '@angular/core/testing';
|
import { async, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ function xyzPhoneData(): PhoneData {
|
|||||||
|
|
||||||
class MockPhone {
|
class MockPhone {
|
||||||
get(id: string): Observable<PhoneData> {
|
get(id: string): Observable<PhoneData> {
|
||||||
return Observable.of(xyzPhoneData());
|
return of(xyzPhoneData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { SpyLocation } from '@angular/common/testing';
|
import { SpyLocation } from '@angular/common/testing';
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ class ActivatedRouteMock {
|
|||||||
|
|
||||||
class MockPhone {
|
class MockPhone {
|
||||||
query(): Observable<PhoneData[]> {
|
query(): Observable<PhoneData[]> {
|
||||||
return Observable.of([
|
return of([
|
||||||
{name: 'Nexus S', snippet: '', images: []},
|
{name: 'Nexus S', snippet: '', images: []},
|
||||||
{name: 'Motorola DROID', snippet: '', images: []}
|
{name: 'Motorola DROID', snippet: '', images: []}
|
||||||
]);
|
]);
|
||||||
|
@ -9,10 +9,8 @@
|
|||||||
"lib": ["es2015", "dom"],
|
"lib": ["es2015", "dom"],
|
||||||
"removeComments": false,
|
"removeComments": false,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"suppressImplicitAnyIndexErrors": true,
|
"skipLibCheck": true,
|
||||||
"typeRoots": [
|
"suppressImplicitAnyIndexErrors": true
|
||||||
"./node_modules/@types/"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"files": [
|
"files": [
|
||||||
@ -21,7 +19,6 @@
|
|||||||
],
|
],
|
||||||
|
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"genDir": "aot",
|
|
||||||
"skipMetadataEmit" : true
|
"skipMetadataEmit" : true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,8 @@
|
|||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"lib": [ "es2015", "dom" ],
|
"lib": [ "es2015", "dom" ],
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"suppressImplicitAnyIndexErrors": true,
|
"skipLibCheck": true,
|
||||||
"typeRoots": [
|
"suppressImplicitAnyIndexErrors": true
|
||||||
"./node_modules/@types/"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"compileOnSave": true,
|
"compileOnSave": true,
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
// #enddocregion activatedroute
|
// #enddocregion activatedroute
|
||||||
import { Observable } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
|
|
||||||
import { async, TestBed } from '@angular/core/testing';
|
import { async, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ function xyzPhoneData(): PhoneData {
|
|||||||
|
|
||||||
class MockPhone {
|
class MockPhone {
|
||||||
get(id: string): Observable<PhoneData> {
|
get(id: string): Observable<PhoneData> {
|
||||||
return Observable.of(xyzPhoneData());
|
return of(xyzPhoneData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// #docregion routestuff
|
// #docregion routestuff
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { SpyLocation } from '@angular/common/testing';
|
import { SpyLocation } from '@angular/common/testing';
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ class ActivatedRouteMock {
|
|||||||
|
|
||||||
class MockPhone {
|
class MockPhone {
|
||||||
query(): Observable<PhoneData[]> {
|
query(): Observable<PhoneData[]> {
|
||||||
return Observable.of([
|
return of([
|
||||||
{name: 'Nexus S', snippet: '', images: []},
|
{name: 'Nexus S', snippet: '', images: []},
|
||||||
{name: 'Motorola DROID', snippet: '', images: []}
|
{name: 'Motorola DROID', snippet: '', images: []}
|
||||||
]);
|
]);
|
||||||
|
@ -8,10 +8,8 @@
|
|||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"lib": [ "es2015", "dom" ],
|
"lib": [ "es2015", "dom" ],
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"suppressImplicitAnyIndexErrors": true,
|
"skipLibCheck": true,
|
||||||
"typeRoots": [
|
"suppressImplicitAnyIndexErrors": true
|
||||||
"./node_modules/@types/"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"compileOnSave": true,
|
"compileOnSave": true,
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
var path = require('path');
|
|
||||||
|
|
||||||
var _root = path.resolve(__dirname, '..');
|
|
||||||
|
|
||||||
function root(args) {
|
|
||||||
args = Array.prototype.slice.call(arguments, 0);
|
|
||||||
return path.join.apply(path, [_root].concat(args));
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.root = root;
|
|
||||||
// #enddocregion
|
|
@ -1,17 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
Error.stackTraceLimit = Infinity;
|
|
||||||
|
|
||||||
require('core-js/es6');
|
|
||||||
require('core-js/es7/reflect');
|
|
||||||
|
|
||||||
require('zone.js/dist/zone');
|
|
||||||
require('zone.js/dist/zone-testing');
|
|
||||||
|
|
||||||
var appContext = require.context('../src', true, /\.spec\.ts/);
|
|
||||||
|
|
||||||
appContext.keys().forEach(appContext);
|
|
||||||
|
|
||||||
var testing = require('@angular/core/testing');
|
|
||||||
var browser = require('@angular/platform-browser-dynamic/testing');
|
|
||||||
|
|
||||||
testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting());
|
|
@ -1,39 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
var webpackConfig = require('./webpack.test');
|
|
||||||
|
|
||||||
module.exports = function (config) {
|
|
||||||
var _config = {
|
|
||||||
basePath: '',
|
|
||||||
|
|
||||||
frameworks: ['jasmine'],
|
|
||||||
|
|
||||||
files: [
|
|
||||||
{pattern: './config/karma-test-shim.js', watched: false}
|
|
||||||
],
|
|
||||||
|
|
||||||
preprocessors: {
|
|
||||||
'./config/karma-test-shim.js': ['webpack', 'sourcemap']
|
|
||||||
},
|
|
||||||
|
|
||||||
webpack: webpackConfig,
|
|
||||||
|
|
||||||
webpackMiddleware: {
|
|
||||||
stats: 'errors-only'
|
|
||||||
},
|
|
||||||
|
|
||||||
webpackServer: {
|
|
||||||
noInfo: true
|
|
||||||
},
|
|
||||||
|
|
||||||
reporters: ['progress', 'kjhtml'],
|
|
||||||
port: 9876,
|
|
||||||
colors: true,
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
autoWatch: false,
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
singleRun: true
|
|
||||||
};
|
|
||||||
|
|
||||||
config.set(_config);
|
|
||||||
};
|
|
||||||
// #enddocregion
|
|
@ -1,81 +0,0 @@
|
|||||||
// #docplaster
|
|
||||||
// #docregion
|
|
||||||
var webpack = require('webpack');
|
|
||||||
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
||||||
var ExtractTextPlugin = require('extract-text-webpack-plugin');
|
|
||||||
var helpers = require('./helpers');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// #docregion entries, one-entry, two-entries
|
|
||||||
entry: {
|
|
||||||
// #enddocregion one-entry, two-entries
|
|
||||||
'polyfills': './src/polyfills.ts',
|
|
||||||
// #docregion two-entries
|
|
||||||
'vendor': './src/vendor.ts',
|
|
||||||
// #docregion one-entry
|
|
||||||
'app': './src/main.ts'
|
|
||||||
},
|
|
||||||
// #enddocregion entries, one-entry, two-entries
|
|
||||||
|
|
||||||
// #docregion resolve
|
|
||||||
resolve: {
|
|
||||||
extensions: ['.ts', '.js']
|
|
||||||
},
|
|
||||||
// #enddocregion resolve
|
|
||||||
|
|
||||||
// #docregion loaders
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.ts$/,
|
|
||||||
loaders: [
|
|
||||||
{
|
|
||||||
loader: 'awesome-typescript-loader',
|
|
||||||
options: { configFileName: helpers.root('src', 'tsconfig.json') }
|
|
||||||
} , 'angular2-template-loader'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.html$/,
|
|
||||||
loader: 'html-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
|
|
||||||
loader: 'file-loader?name=assets/[name].[hash].[ext]'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
exclude: helpers.root('src', 'app'),
|
|
||||||
loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap' })
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
include: helpers.root('src', 'app'),
|
|
||||||
loader: 'raw-loader'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
// #enddocregion loaders
|
|
||||||
|
|
||||||
// #docregion plugins
|
|
||||||
plugins: [
|
|
||||||
// Workaround for angular/angular#11580
|
|
||||||
new webpack.ContextReplacementPlugin(
|
|
||||||
// The (\\|\/) piece accounts for path separators in *nix and Windows
|
|
||||||
/angular(\\|\/)core(\\|\/)@angular/,
|
|
||||||
helpers.root('./src'), // location of your src
|
|
||||||
{} // a map of your routes
|
|
||||||
),
|
|
||||||
|
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
|
||||||
name: ['app', 'vendor', 'polyfills']
|
|
||||||
}),
|
|
||||||
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: 'src/index.html'
|
|
||||||
})
|
|
||||||
]
|
|
||||||
// #enddocregion plugins
|
|
||||||
};
|
|
||||||
// #enddocregion
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
var webpackMerge = require('webpack-merge');
|
|
||||||
var ExtractTextPlugin = require('extract-text-webpack-plugin');
|
|
||||||
var commonConfig = require('./webpack.common.js');
|
|
||||||
var helpers = require('./helpers');
|
|
||||||
|
|
||||||
module.exports = webpackMerge(commonConfig, {
|
|
||||||
devtool: 'cheap-module-eval-source-map',
|
|
||||||
|
|
||||||
output: {
|
|
||||||
path: helpers.root('dist'),
|
|
||||||
publicPath: '/',
|
|
||||||
filename: '[name].js',
|
|
||||||
chunkFilename: '[id].chunk.js'
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
new ExtractTextPlugin('[name].css')
|
|
||||||
],
|
|
||||||
|
|
||||||
devServer: {
|
|
||||||
historyApiFallback: true,
|
|
||||||
stats: 'minimal'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// #enddocregion
|
|
@ -1,41 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
var webpack = require('webpack');
|
|
||||||
var webpackMerge = require('webpack-merge');
|
|
||||||
var ExtractTextPlugin = require('extract-text-webpack-plugin');
|
|
||||||
var commonConfig = require('./webpack.common.js');
|
|
||||||
var helpers = require('./helpers');
|
|
||||||
|
|
||||||
const ENV = process.env.NODE_ENV = process.env.ENV = 'production';
|
|
||||||
|
|
||||||
module.exports = webpackMerge(commonConfig, {
|
|
||||||
devtool: 'source-map',
|
|
||||||
|
|
||||||
output: {
|
|
||||||
path: helpers.root('dist'),
|
|
||||||
publicPath: '/',
|
|
||||||
filename: '[name].[hash].js',
|
|
||||||
chunkFilename: '[id].[hash].chunk.js'
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
new webpack.NoEmitOnErrorsPlugin(),
|
|
||||||
new webpack.optimize.UglifyJsPlugin({ // https://github.com/angular/angular/issues/10618
|
|
||||||
mangle: {
|
|
||||||
keep_fnames: true
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
new ExtractTextPlugin('[name].[hash].css'),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env': {
|
|
||||||
'ENV': JSON.stringify(ENV)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
new webpack.LoaderOptionsPlugin({
|
|
||||||
htmlLoader: {
|
|
||||||
minimize: false // workaround for ng2
|
|
||||||
}
|
|
||||||
})
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
// #enddocregion
|
|
@ -1,55 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
var webpack = require('webpack');
|
|
||||||
var helpers = require('./helpers');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
devtool: 'inline-source-map',
|
|
||||||
|
|
||||||
resolve: {
|
|
||||||
extensions: ['.ts', '.js']
|
|
||||||
},
|
|
||||||
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.ts$/,
|
|
||||||
loaders: [
|
|
||||||
{
|
|
||||||
loader: 'awesome-typescript-loader',
|
|
||||||
options: { configFileName: helpers.root('src', 'tsconfig.json') }
|
|
||||||
} , 'angular2-template-loader'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.html$/,
|
|
||||||
loader: 'html-loader'
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
|
|
||||||
loader: 'null-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
exclude: helpers.root('src', 'app'),
|
|
||||||
loader: 'null-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
include: helpers.root('src', 'app'),
|
|
||||||
loader: 'raw-loader'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
new webpack.ContextReplacementPlugin(
|
|
||||||
// The (\\|\/) piece accounts for path separators in *nix and Windows
|
|
||||||
/angular(\\|\/)core(\\|\/)@angular/,
|
|
||||||
helpers.root('./src'), // location of your src
|
|
||||||
{} // a map of your routes
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
// #enddocregion
|
|
@ -1,21 +0,0 @@
|
|||||||
'use strict'; // necessary for es6 output in node
|
|
||||||
|
|
||||||
import { browser, element, by } from 'protractor';
|
|
||||||
|
|
||||||
describe('QuickStart E2E Tests', function () {
|
|
||||||
|
|
||||||
let expectedMsg = 'Hello from Angular App with Webpack';
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
browser.get('');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should display: ${expectedMsg}`, function () {
|
|
||||||
expect(element(by.css('h1')).getText()).toEqual(expectedMsg);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display an image', function () {
|
|
||||||
expect(element(by.css('img')).isPresent()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"build": "build:webpack",
|
|
||||||
"run": "serve:cli",
|
|
||||||
"projectType": "systemjs"
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
module.exports = require('./config/karma.conf.js');
|
|
@ -1,49 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "angular2-webpack",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "A webpack starter for Angular",
|
|
||||||
"scripts": {
|
|
||||||
"start": "webpack-dev-server --inline --progress --port 8080",
|
|
||||||
"test": "karma start",
|
|
||||||
"build": "rimraf dist && webpack --config config/webpack.prod.js --progress --profile --bail"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@angular/common": "~4.2.0",
|
|
||||||
"@angular/compiler": "~4.2.0",
|
|
||||||
"@angular/core": "~4.2.0",
|
|
||||||
"@angular/forms": "~4.2.0",
|
|
||||||
"@angular/http": "~4.2.0",
|
|
||||||
"@angular/platform-browser": "~4.2.0",
|
|
||||||
"@angular/platform-browser-dynamic": "~4.2.0",
|
|
||||||
"@angular/router": "~4.2.0",
|
|
||||||
"core-js": "^2.4.1",
|
|
||||||
"rxjs": "5.0.1",
|
|
||||||
"zone.js": "^0.8.4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^6.0.45",
|
|
||||||
"@types/jasmine": "2.5.36",
|
|
||||||
"angular2-template-loader": "^0.6.0",
|
|
||||||
"awesome-typescript-loader": "^3.0.4",
|
|
||||||
"css-loader": "^0.26.1",
|
|
||||||
"extract-text-webpack-plugin": "2.0.0-beta.5",
|
|
||||||
"file-loader": "^0.9.0",
|
|
||||||
"html-loader": "^0.4.3",
|
|
||||||
"html-webpack-plugin": "^2.16.1",
|
|
||||||
"jasmine-core": "^2.4.1",
|
|
||||||
"karma": "^1.2.0",
|
|
||||||
"karma-chrome-launcher": "^2.0.0",
|
|
||||||
"karma-jasmine": "^1.0.2",
|
|
||||||
"karma-sourcemap-loader": "^0.3.7",
|
|
||||||
"karma-webpack": "^2.0.1",
|
|
||||||
"null-loader": "^0.1.1",
|
|
||||||
"raw-loader": "^0.5.1",
|
|
||||||
"rimraf": "^2.5.2",
|
|
||||||
"style-loader": "^0.13.1",
|
|
||||||
"typescript": "~2.3.1",
|
|
||||||
"webpack": "2.2.1",
|
|
||||||
"webpack-dev-server": "2.4.1",
|
|
||||||
"webpack-merge": "^3.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
/* #docregion */
|
|
||||||
main {
|
|
||||||
padding: 1em;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 50px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
/* #enddocregion */
|
|
@ -1,7 +0,0 @@
|
|||||||
<!-- #docregion -->
|
|
||||||
<main>
|
|
||||||
<h1>Hello from Angular App with Webpack</h1>
|
|
||||||
|
|
||||||
<img src="../assets/images/angular.png">
|
|
||||||
</main>
|
|
||||||
<!-- #enddocregion -->
|
|
@ -1,16 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
|
||||||
|
|
||||||
describe('App', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
TestBed.configureTestingModule({ declarations: [AppComponent]});
|
|
||||||
});
|
|
||||||
|
|
||||||
it ('should work', () => {
|
|
||||||
let fixture = TestBed.createComponent(AppComponent);
|
|
||||||
expect(fixture.componentInstance instanceof AppComponent).toBe(true, 'should create AppComponent');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// #enddocregion
|
|
@ -1,16 +0,0 @@
|
|||||||
// #docplaster
|
|
||||||
// #docregion
|
|
||||||
// #docregion component
|
|
||||||
import { Component } from '@angular/core';
|
|
||||||
|
|
||||||
// #enddocregion component
|
|
||||||
import '../assets/css/styles.css';
|
|
||||||
|
|
||||||
// #docregion component
|
|
||||||
@Component({
|
|
||||||
selector: 'my-app',
|
|
||||||
templateUrl: './app.component.html',
|
|
||||||
styleUrls: ['./app.component.css']
|
|
||||||
})
|
|
||||||
export class AppComponent { }
|
|
||||||
// #enddocregion
|
|
@ -1,16 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [
|
|
||||||
BrowserModule
|
|
||||||
],
|
|
||||||
declarations: [
|
|
||||||
AppComponent
|
|
||||||
],
|
|
||||||
bootstrap: [ AppComponent ]
|
|
||||||
})
|
|
||||||
export class AppModule { }
|
|
@ -1,6 +0,0 @@
|
|||||||
/* #docregion */
|
|
||||||
body {
|
|
||||||
background: #0147A7;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
/* #enddocregion */
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.3 KiB |
@ -1,14 +0,0 @@
|
|||||||
<!-- #docregion -->
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<base href="/">
|
|
||||||
<title>Angular With Webpack</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<my-app>Loading...</my-app>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
<!-- #enddocregion -->
|
|
@ -1,14 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
|
||||||
import { enableProdMode } from '@angular/core';
|
|
||||||
|
|
||||||
import { AppModule } from './app/app.module';
|
|
||||||
|
|
||||||
// #docregion enable-prod
|
|
||||||
if (process.env.ENV === 'production') {
|
|
||||||
enableProdMode();
|
|
||||||
}
|
|
||||||
// #enddocregion enable-prod
|
|
||||||
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
|
||||||
// #enddocregion
|
|
@ -1,12 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
import 'core-js/es6';
|
|
||||||
import 'core-js/es7/reflect';
|
|
||||||
require('zone.js/dist/zone');
|
|
||||||
|
|
||||||
if (process.env.ENV === 'production') {
|
|
||||||
// Production
|
|
||||||
} else {
|
|
||||||
// Development and test
|
|
||||||
Error['stackTraceLimit'] = Infinity;
|
|
||||||
require('zone.js/dist/long-stack-trace-zone');
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es5",
|
|
||||||
"module": "commonjs",
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"sourceMap": true,
|
|
||||||
"emitDecoratorMetadata": true,
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"lib": ["es2015", "dom"],
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"suppressImplicitAnyIndexErrors": true
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
// TODO(i): this no longer works. we need to review this example and if absolutely necessary rewrite it to use the
|
|
||||||
// rxjs-compat package
|
|
||||||
|
|
||||||
// #docregion
|
|
||||||
// Angular
|
|
||||||
import '@angular/platform-browser';
|
|
||||||
import '@angular/platform-browser-dynamic';
|
|
||||||
import '@angular/core';
|
|
||||||
import '@angular/common';
|
|
||||||
import '@angular/http';
|
|
||||||
import '@angular/router';
|
|
||||||
|
|
||||||
// RxJS
|
|
||||||
import 'rxjs';
|
|
||||||
|
|
||||||
// Other vendors for example jQuery, Lodash or Bootstrap
|
|
||||||
// You can import js, ts, css, sass, ...
|
|
||||||
// #enddocregion
|
|
@ -1,3 +0,0 @@
|
|||||||
// #docregion
|
|
||||||
module.exports = require('./config/webpack.dev.js');
|
|
||||||
// #enddocregion
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"files":[
|
|
||||||
"!**/*.d.ts",
|
|
||||||
"!**/*.js",
|
|
||||||
"!**/*.[0-9].*",
|
|
||||||
"config/**/*",
|
|
||||||
"webpack.config.js",
|
|
||||||
"karma.webpack.conf.js"
|
|
||||||
],
|
|
||||||
"removeSystemJsConfig": true,
|
|
||||||
"type": "webpack"
|
|
||||||
}
|
|
@ -895,7 +895,7 @@ For more information on pipes, see [Pipes](guide/pipes).
|
|||||||
### lowercase
|
### lowercase
|
||||||
|
|
||||||
<code-example hideCopy>
|
<code-example hideCopy>
|
||||||
<div>{{movie.title | lowercase}}</div>
|
<td>{{movie.title | lowercase}}</td>
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,6 +97,9 @@ You can control your app compilation by providing template compiler options in t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
### *enableResourceInlining*
|
||||||
|
This options tell the compiler to replace the `templateUrl` and `styleUrls` property in all `@Component` decorators with inlined contents in `template` and `styles` properties.
|
||||||
|
When enabled, the `.js` output of ngc will have no lazy-loaded `templateUrl` or `styleUrls`.
|
||||||
|
|
||||||
### *skipMetadataEmit*
|
### *skipMetadataEmit*
|
||||||
|
|
||||||
|
@ -1,175 +0,0 @@
|
|||||||
<div class="breadcrumb">
|
|
||||||
<a href="#">API<a> / <a href="#">@core<a>
|
|
||||||
</div>
|
|
||||||
<header class="api-header">
|
|
||||||
<h1><label class="api-status-label experimental">experimental</label><label class="api-type-label class">class</label>Class Name</h1>
|
|
||||||
</header>
|
|
||||||
<div class="page-actions">
|
|
||||||
<a href="#"><label class="raised page-label"><i class="material-icons">mode_edit</i>suggest edits</label></a>
|
|
||||||
<a href="#"><label class="raised page-label"><i class="material-icons">code</i>view source</label></a>
|
|
||||||
</div>
|
|
||||||
<p>Class description goes here. This is a short and to the point one or two sentence description that easily introduces the reader to the class.</p>
|
|
||||||
<div class="api-body">
|
|
||||||
<section>
|
|
||||||
<h2>Overview</h2>
|
|
||||||
<code-example language="ts" hidecopy="true" ng-version="5.2.0"><aio-code class="simple-code" ng-reflect-ng-class="[object Object]" ng-reflect-code="
|
|
||||||
class <a href="api/core/Compi" ng-reflect-hide-copy="true" ng-reflect-language="ts" ng-reflect-linenums="" ng-reflect-path="" ng-reflect-region="" ng-reflect-title=""><pre class="prettyprint lang-ts">
|
|
||||||
<code class="animated fadeIn"><span class="kwd">class</span><span class="pln"> </span><a href="api/core/Compiler" class="code-anchor"><span class="typ">Compiler</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
|
||||||
</span><a class="code-anchor" href="api/core/Compiler#compileModuleSync"><span class="pln">compileModuleSync</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>):</span><span class="pln"> </span><span class="typ">NgModuleFactory</span><span class="pun"><</span><span class="pln">T</span><span class="pun">></span></a><span class="pln">
|
|
||||||
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAsync"><span class="pln">compileModuleAsync</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>):</span><span class="pln"> </span><span class="typ">Promise</span><span class="pun"><</span><span class="typ">NgModuleFactory</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>></span></a><span class="pln">
|
|
||||||
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAndAllComponentsSync"><span class="pln">compileModuleAndAllComponentsSync</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>):</span><span class="pln"> </span><span class="typ">ModuleWithComponentFactories</span><span class="pun"><</span><span class="pln">T</span><span class="pun">></span></a><span class="pln">
|
|
||||||
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAndAllComponentsAsync"><span class="pln">compileModuleAndAllComponentsAsync</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>):</span><span class="pln"> </span><span class="typ">Promise</span><span class="pun"><</span><span class="typ">ModuleWithComponentFactories</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>></span></a><span class="pln">
|
|
||||||
</span><a class="code-anchor" href="api/core/Compiler#clearCache"><span class="pln">clearCache</span><span class="pun">():</span><span class="pln"> </span><span class="kwd">void</span></a><span class="pln">
|
|
||||||
</span><a class="code-anchor" href="api/core/Compiler#clearCacheFor"><span class="pln">clearCacheFor</span><span class="pun">(</span><span class="pln">type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">any</span><span class="pun">>)</span></a><span class="pln">
|
|
||||||
</span><span class="pun">}</span></code>
|
|
||||||
</pre></aio-code></code-example>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>Description</h2>
|
|
||||||
<p>The longer class description goes here which can include multiple paragraphs.</p>
|
|
||||||
</p>Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.</p>
|
|
||||||
<h3>Subclasses</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="#">Subclass1</a></li>
|
|
||||||
<li><a href="#">Subclass2</a></li>
|
|
||||||
<li><a href="#">Subclass3</a></li>
|
|
||||||
</ul>
|
|
||||||
<h3>See Also</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="#">Link1</a></li>
|
|
||||||
<li><a href="#">Link2</a></li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>Constructor</h2>
|
|
||||||
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
|
|
||||||
<aio-code class="simple-code"><pre class="prettyprint lang-">
|
|
||||||
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
|
||||||
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
|
|
||||||
</span><span class="pun">}[],</span><span class="pln"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
|
|
||||||
</pre></aio-code></code-example>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>Properties</h2>
|
|
||||||
<table class="is-full-width list-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Property</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code><strong>Property1</strong></code>
|
|
||||||
</td>
|
|
||||||
<td><label class="property-type-label type">Type</label></td>
|
|
||||||
<td>Description goes here</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code><strong>Property2</strong></code>
|
|
||||||
</td>
|
|
||||||
<td>Type</td>
|
|
||||||
<td>Description goes here</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code><strong>Property3</strong></code>
|
|
||||||
</td>
|
|
||||||
<td>Type</td>
|
|
||||||
<td>Description goes here</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
|
||||||
<section class="api-method">
|
|
||||||
<h2>Methods</h2>
|
|
||||||
<table class="is-full-width item-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Method1Name( )</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>Description goes here</p>
|
|
||||||
<br>
|
|
||||||
<p>Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table class="is-full-width api-method item-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Method2Name( )</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>Description goes here</p>
|
|
||||||
<hr>
|
|
||||||
<h5>Declaration</h5>
|
|
||||||
<code-example language="ts" hidecopy="true" ng-version="5.2.0">
|
|
||||||
<aio-code class="simple-code"><pre class="prettyprint lang-ts">
|
|
||||||
<code class="animated fadeIn"><span class="kwd">class</span><span class="pln"> </span><a href="api/animations/AnimationBuilder" class="code-anchor"><span class="typ">AnimationBuilder</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln"></span><a class="code-anchor" href="api/animations/AnimationBuilder#build"><span class="pln">build</span><span class="pun">(</span><span class="pln">animation</span><span class="pun">:</span><span class="pln"> </span><span class="typ">AnimationMetadata</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">AnimationMetadata</span><span class="pun">[]):</span><span class="pln"> </span><span class="typ">AnimationFactory</span></a><span class="pln"></span><span class="pun">}</span></code></pre>
|
|
||||||
</aio-code>
|
|
||||||
</code-example>
|
|
||||||
<h6>Parameters</h6>
|
|
||||||
<h6>Returns</h6>
|
|
||||||
<p>Returns information and results goes here.</p>
|
|
||||||
<h6>Errors</h6>
|
|
||||||
<p>Error information goes here</p>
|
|
||||||
<hr>
|
|
||||||
<p>Further details provided as needed. Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball.</p><hr>
|
|
||||||
<h6>Overloads</h6>
|
|
||||||
<table class="is-full-width">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
|
|
||||||
<aio-code class="simple-code"><pre class="prettyprint lang-">
|
|
||||||
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
|
||||||
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
|
|
||||||
</span><span class="pun">}[],</span><span class="pln"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
|
|
||||||
</pre></aio-code></code-example>
|
|
||||||
</td>
|
|
||||||
<td>Description goes here</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
|
|
||||||
<aio-code class="simple-code"><pre class="prettyprint lang-">
|
|
||||||
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
|
||||||
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
|
|
||||||
</span><span class="pun">}[],</span><span class="pln"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
|
|
||||||
</pre></aio-code></code-example>
|
|
||||||
</td>
|
|
||||||
<td>Description goes here</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
<h5>Example: Descriptive Title of Method Example</h5>
|
|
||||||
<p>Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>Example: Descriptive Title of Combined Example Goes Here</h2>
|
|
||||||
<p>Intro description text about what the example is and how it can be used.</p>
|
|
||||||
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
|
|
||||||
<aio-code class="simple-code"><pre class="prettyprint lang-">
|
|
||||||
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
|
||||||
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
|
|
||||||
</span><span class="pun">}[],</span><span class="pln"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
|
|
||||||
</pre></aio-code></code-example>
|
|
||||||
<p>Further explanation provided as needed. Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball.</p>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
@ -8,9 +8,10 @@ A _component_ controls a patch of screen called a *view*. For example, individua
|
|||||||
* The list of heroes.
|
* The list of heroes.
|
||||||
* The hero editor.
|
* The hero editor.
|
||||||
|
|
||||||
You define a component's application logic—what it does to support the view—inside a class. The class interacts with the view through an API of properties and methods.
|
You define a component's application logic—what it does to support the view—inside a class.
|
||||||
|
The class interacts with the view through an API of properties and methods.
|
||||||
|
|
||||||
For example, the `HeroListComponent` has a `heroes` property that returns an array of heroes that it acquires from a service. `HeroListComponent` also has a `selectHero()` method that sets a `selectedHero` property when the user clicks to choose a hero from that list.
|
For example, the `HeroListComponent` has a `heroes` property that holds an array of heroes. It also has a `selectHero()` method that sets a `selectedHero` property when the user clicks to choose a hero from that list. The component acquires the heroes from a service, which is a TypeScript [parameter property[(http://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties) on the constructor. The service is provided to the component through the dependency injection system.
|
||||||
|
|
||||||
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (class)" region="class"></code-example>
|
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (class)" region="class"></code-example>
|
||||||
|
|
||||||
@ -39,8 +40,7 @@ Angular inserts an instance of the `HeroListComponent` view between those tags.
|
|||||||
|
|
||||||
* `templateUrl`: The module-relative address of this component's HTML template. Alternatively, you can provide the HTML template inline, as the value of the `template` property. This template defines the component's _host view_.
|
* `templateUrl`: The module-relative address of this component's HTML template. Alternatively, you can provide the HTML template inline, as the value of the `template` property. This template defines the component's _host view_.
|
||||||
|
|
||||||
* `providers`: An array of **dependency injection providers** for services that the component requires. In the example, this tells Angular that the component's constructor requires a `HeroService` instance
|
* `providers`: An array of **dependency injection providers** for services that the component requires. In the example, this tells Angular how provide the `HeroService` instance that the component's constructor uses to get the list of heroes to display.
|
||||||
in order to get the list of heroes to display.
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
|
@ -88,7 +88,8 @@ For example, import Angular's `Component` decorator from the `@angular/core` lib
|
|||||||
|
|
||||||
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
|
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
|
||||||
|
|
||||||
You also import NgModules from Angular _libraries_ using JavaScript import statements:
|
You also import NgModules from Angular _libraries_ using JavaScript import statements.
|
||||||
|
For example, the following code imports the `BrowserModule` NgModule from the `platform-browser` library:
|
||||||
|
|
||||||
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module" linenums="false"></code-example>
|
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module" linenums="false"></code-example>
|
||||||
|
|
||||||
|
@ -60,11 +60,29 @@ The process of `HeroService` injection looks something like this:
|
|||||||
|
|
||||||
### Providing services
|
### Providing services
|
||||||
|
|
||||||
You must register at least one *provider* of any service you are going to use. You can register providers in modules or in components.
|
You must register at least one *provider* of any service you are going to use. A service can register providers itself, making it available everywhere, or you can register providers with specific modules or components. You register providers in the metadata of the service (in the `@Injectable` decorator), or in the `@NgModule` or `@Component` metadata
|
||||||
|
|
||||||
* When you add providers to the [root module](guide/architecture-modules), the same instance of a service is available to all components in your app.
|
* 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:
|
||||||
|
|
||||||
<code-example path="architecture/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (module providers)" region="providers"></code-example>
|
```
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
When you provide the service at the root level, Angular creates a single, shared instance of HeroService and injects into any class that asks for it. Registering the provider in the `@Injectable` metadata also allows Angular to optimize an app by removing the service if it turns out not to be used after all.
|
||||||
|
|
||||||
|
* When you register a provider with a [specific NgModule](guide/architecture-modules), the same instance of a service is available to all components in that NgModule. To register at this level, use the `providers` property of the `@NgModule` decorator:
|
||||||
|
|
||||||
|
```
|
||||||
|
@NgModule({
|
||||||
|
providers: [
|
||||||
|
BackendService,
|
||||||
|
Logger
|
||||||
|
],
|
||||||
|
...
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
* When you register a provider at the component level, you get a new instance of the
|
* When you register a provider at the component level, you get a new instance of the
|
||||||
service with each new instance of that component. At the component level, register a service provider in the `providers` property of the `@Component` metadata:
|
service with each new instance of that component. At the component level, register a service provider in the `providers` property of the `@Component` metadata:
|
||||||
|
@ -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-styles` flag.
|
The CLI 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
|
||||||
@ -189,7 +189,7 @@ They are _not inherited_ by any components nested within the template nor by any
|
|||||||
|
|
||||||
<div class="l-sub-section">
|
<div class="l-sub-section">
|
||||||
|
|
||||||
You can specify more than one styles file or even a combination of `style` and `styleUrls`.
|
You can specify more than one styles file or even a combination of `styles` and `styleUrls`.
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -280,12 +280,14 @@ To control how this encapsulation happens on a *per
|
|||||||
component* basis, you can set the *view encapsulation mode* in the component metadata.
|
component* basis, you can set the *view encapsulation mode* in the component metadata.
|
||||||
Choose from the following modes:
|
Choose from the following modes:
|
||||||
|
|
||||||
* `Native` view encapsulation uses the browser's native shadow DOM implementation (see
|
* `ShadowDom` view encapsulation uses the browser's native shadow DOM implementation (see
|
||||||
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
|
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
|
||||||
on the [MDN](https://developer.mozilla.org) site)
|
on the [MDN](https://developer.mozilla.org) site)
|
||||||
to attach a shadow DOM to the component's host element, and then puts the component
|
to attach a shadow DOM to the component's host element, and then puts the component
|
||||||
view inside that shadow DOM. The component's styles are included within the shadow DOM.
|
view inside that shadow DOM. The component's styles are included within the shadow DOM.
|
||||||
|
|
||||||
|
* `Native` view encapsulation uses a now deprecated version of the browser's native shadow DOM implementation - [learn about the changes](https://hayato.io/2016/shadowdomv1/).
|
||||||
|
|
||||||
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
|
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
|
||||||
(and renaming) the CSS code to effectively scope the CSS to the component's view.
|
(and renaming) the CSS code to effectively scope the CSS to the component's view.
|
||||||
For details, see [Appendix 1](guide/component-styles#inspect-generated-css).
|
For details, see [Appendix 1](guide/component-styles#inspect-generated-css).
|
||||||
@ -300,8 +302,8 @@ To set the components encapsulation mode, use the `encapsulation` property in th
|
|||||||
<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" title="src/app/quest-summary.component.ts" linenums="false">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
`Native` view encapsulation only works on browsers that have native support
|
`ShadowDom` view encapsulation only works on browsers that have native support
|
||||||
for shadow DOM (see [Shadow DOM v0](http://caniuse.com/#feat=shadowdom) on the
|
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
|
||||||
[Can I use](http://caniuse.com) site). The support is still limited,
|
[Can I use](http://caniuse.com) site). The support is still limited,
|
||||||
which is why `Emulated` view encapsulation is the default mode and recommended
|
which is why `Emulated` view encapsulation is the default mode and recommended
|
||||||
in most cases.
|
in most cases.
|
||||||
|
@ -32,7 +32,7 @@ from the [The Tour of Heroes](tutorial/).
|
|||||||
</code-tabs>
|
</code-tabs>
|
||||||
|
|
||||||
The `HeroesComponent` is the top-level heroes component.
|
The `HeroesComponent` is the top-level heroes component.
|
||||||
It's only purpose is to display the `HeroListComponent`
|
Its only purpose is to display the `HeroListComponent`
|
||||||
which displays a list of hero names.
|
which displays a list of hero names.
|
||||||
|
|
||||||
This version of the `HeroListComponent` gets its `heroes` from the `HEROES` array, an in-memory collection
|
This version of the `HeroListComponent` gets its `heroes` from the `HEROES` array, an in-memory collection
|
||||||
|
@ -152,7 +152,7 @@ Install `source-map-explorer`:
|
|||||||
Build your app for production _including the source maps_
|
Build your app for production _including the source maps_
|
||||||
|
|
||||||
<code-example language="none" class="code-shell">
|
<code-example language="none" class="code-shell">
|
||||||
ng build --prod --sourcemaps
|
ng build --prod --source-map
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
List the generated bundles in the `dist/` folder.
|
List the generated bundles in the `dist/` folder.
|
||||||
|
@ -31,6 +31,8 @@ Here are a few essential commands for guide page authors.
|
|||||||
|
|
||||||
1. http://localhost:4200/ — browse to the app running locally.
|
1. http://localhost:4200/ — browse to the app running locally.
|
||||||
|
|
||||||
|
You can combine `yarn docs-watch` and `yarn start` into one command with `yarn serve-and-sync`.
|
||||||
|
|
||||||
## Guide pages
|
## Guide pages
|
||||||
|
|
||||||
All but a few guide pages are [markdown](https://daringfireball.net/projects/markdown/syntax "markdown") files with an `.md` extension.
|
All but a few guide pages are [markdown](https://daringfireball.net/projects/markdown/syntax "markdown") files with an `.md` extension.
|
||||||
|
@ -92,7 +92,7 @@ built-in validators—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.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" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
Note that:
|
Note that:
|
||||||
@ -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.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" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
### Adding to template-driven forms
|
### Adding to template-driven forms
|
||||||
@ -208,5 +208,80 @@ set the color of each form control's border.
|
|||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
## Cross field validation
|
||||||
|
This section shows how to perform cross field validation. It assumes some basic knowledge of creating custom validators.
|
||||||
|
|
||||||
|
<div class="l-sub-section">
|
||||||
|
|
||||||
|
If you haven't created custom validators before, start by reviewing the [custom validators section](guide/form-validation#custom-validators).
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
In the following section, we will make sure that our heroes do not reveal their true identities by filling out the Hero Form. We will do that by validating that the hero names and alter egos do not match.
|
||||||
|
|
||||||
|
### Adding to reactive forms
|
||||||
|
|
||||||
|
The form has the following structure:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const heroForm = new FormGroup({
|
||||||
|
'name': new FormControl(),
|
||||||
|
'alterEgo': new FormControl(),
|
||||||
|
'power': new FormControl()
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that the name and alterEgo are sibling controls. To evaluate both controls in a single custom validator, we should perform the validation in a common ancestor control: the `FormGroup`. That way, we can query the `FormGroup` for the child controls which will allow us to compare their values.
|
||||||
|
|
||||||
|
To add a validator to the `FormGroup`, pass the new validator in as the second argument on creation.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const heroForm = new FormGroup({
|
||||||
|
'name': new FormControl(),
|
||||||
|
'alterEgo': new FormControl(),
|
||||||
|
'power': new FormControl()
|
||||||
|
}, { validators: identityRevealedValidator });
|
||||||
|
```
|
||||||
|
|
||||||
|
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>
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
First we retrieve the child controls by calling the `FormGroup`'s [get](api/forms/AbstractControl#get) method. Then we simply compare the values of the `name` and `alterEgo` controls.
|
||||||
|
|
||||||
|
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.
|
||||||
|
<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>
|
||||||
|
|
||||||
|
Note that we check if:
|
||||||
|
- the `FormGroup` has the cross validation error returned by the `identityRevealed` validator,
|
||||||
|
- the user is yet to [interact](guide/form-validation#why-check-dirty-and-touched) with the form.
|
||||||
|
|
||||||
|
### 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>
|
||||||
|
|
||||||
|
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>
|
||||||
|
|
||||||
|
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>
|
||||||
|
|
||||||
|
Note that we check if:
|
||||||
|
- the form has the cross validation error returned by the `identityRevealed` validator,
|
||||||
|
- the user is yet to [interact](guide/form-validation#why-check-dirty-and-touched) with the form.
|
||||||
|
|
||||||
|
This completes the cross validation example. We managed to:
|
||||||
|
- validate the form based on the values of two sibling controls,
|
||||||
|
- show a descriptive error message after the user interacted with the form and the validation failed.
|
||||||
|
|
||||||
**You can run the <live-example></live-example> to see the complete reactive and template-driven example code.**
|
**You can run the <live-example></live-example> to see the complete reactive and template-driven example code.**
|
||||||
|
@ -152,7 +152,8 @@ nothing to distinguish it from any component you've written before.
|
|||||||
Understanding this component requires only the Angular concepts covered in previous pages.
|
Understanding this component requires only the Angular concepts covered in previous pages.
|
||||||
|
|
||||||
* The code imports the Angular core library and the `Hero` model you just created.
|
* The code imports the Angular core library and the `Hero` model you just created.
|
||||||
* The `@Component` selector value of "hero-form" means you can drop this form in a parent template with a `<hero-form>` tag.
|
* The `@Component` selector value of "app-hero-form" means you can drop this form in a parent
|
||||||
|
template with a `<app-hero-form>` tag.
|
||||||
* The `templateUrl` property points to a separate file for the template HTML.
|
* The `templateUrl` property points to a separate file for the template HTML.
|
||||||
* You defined dummy data for `model` and `powers`, as befits a demo.
|
* You defined dummy data for `model` and `powers`, as befits a demo.
|
||||||
|
|
||||||
|
@ -44,25 +44,25 @@ of some of the things they contain:
|
|||||||
<tr>
|
<tr>
|
||||||
<td><code>FormsModule</code></td>
|
<td><code>FormsModule</code></td>
|
||||||
<td><code>@angular/forms</code></td>
|
<td><code>@angular/forms</code></td>
|
||||||
<td>When you build template driven forms (includes <code>NgModel</code>)</td>
|
<td>When you want to build template driven forms (includes <code>NgModel</code>)</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>ReactiveFormsModule</code></td>
|
<td><code>ReactiveFormsModule</code></td>
|
||||||
<td><code>@angular/forms</code></td>
|
<td><code>@angular/forms</code></td>
|
||||||
<td>When building reactive forms</td>
|
<td>When you want to build reactive forms</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>RouterModule</code></td>
|
<td><code>RouterModule</code></td>
|
||||||
<td><code>@angular/router</code></td>
|
<td><code>@angular/router</code></td>
|
||||||
<td>For Routing and when you want to use <code>RouterLink</code>,<code>.forRoot()</code>, and <code>.forChild()</code></td>
|
<td>When you want to use <code>RouterLink</code>, <code>.forRoot()</code>, and <code>.forChild()</code></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>HttpClientModule</code></td>
|
<td><code>HttpClientModule</code></td>
|
||||||
<td><code>@angular/common/http</code></td>
|
<td><code>@angular/common/http</code></td>
|
||||||
<td>When you to talk to a server</td>
|
<td>When you want to talk to a server</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
@ -114,19 +114,23 @@ The following class types can be declared:
|
|||||||
|
|
||||||
A [decorator](guide/glossary#decorator) statement immediately before a field in a class definition that declares the type of that field. Some examples are `@Input` and `@Output`.
|
A [decorator](guide/glossary#decorator) statement immediately before a field in a class definition that declares the type of that field. Some examples are `@Input` and `@Output`.
|
||||||
|
|
||||||
|
{@a cli}
|
||||||
|
|
||||||
## CLI
|
## CLI
|
||||||
|
|
||||||
The [Angular CLI](https://cli.angular.io/) is a command-line tool that can create a project, add files, and perform a variety of ongoing development tasks such as testing, bundling, and deployment.
|
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 tool supports all stages of the development cycle, including building, testing, bundling, and deployment.
|
||||||
|
|
||||||
Learn more in the [Getting Started](guide/quickstart) guide.
|
* To begin using the CLI for a new project, see [Getting Started](guide/quickstart) guide.
|
||||||
|
* To learn more about the full capabilities of the CLI, see the [Angular CLI documentation].(https://github.com/angular/angular-cli/wiki).
|
||||||
|
|
||||||
{@a component}
|
{@a component}
|
||||||
|
|
||||||
## Component
|
## Component
|
||||||
|
|
||||||
A class with the `@Component` [decorator](guide/glossary#decorator) that associates it with a companion [template](guide/glossary#template).
|
A class with the `@Component` [decorator](guide/glossary#decorator) that associates it with a companion [template](guide/glossary#template). Together, the component and template define a [view](guide/glossary#view).
|
||||||
|
|
||||||
A component is a special type of [directive](guide/glossary#directive) that represents a [view](guide/glossary#view).The `@Component` decorator extends the `@Directive` decorator with template-oriented features.
|
A component is a special type of [directive](guide/glossary#directive).
|
||||||
|
The `@Component` decorator extends the `@Directive` decorator with template-oriented features.
|
||||||
|
|
||||||
An Angular component class is responsible for exposing data and handling most of the view's display and user-interaction logic through [data binding](guide/glossary#data-binding).
|
An Angular component class is responsible for exposing data and handling most of the view's display and user-interaction logic through [data binding](guide/glossary#data-binding).
|
||||||
|
|
||||||
@ -208,7 +212,8 @@ See [Class decorator](guide/glossary#class-decorator), [Class field decorator](g
|
|||||||
|
|
||||||
A design pattern and mechanism for creating and delivering parts of an application (dependencies) to other parts of an application that require them.
|
A design pattern and mechanism for creating and delivering parts of an application (dependencies) to other parts of an application that require them.
|
||||||
|
|
||||||
In Angular, dependencies are typically services, but can also be values, such as strings or functions. An [injector](guide/glossary#injector) for an app (created automatically during bootstrap) creates dependencies when needed, using a registered [provider](guide/glossary#provider) of the service or value. Different providers can provide different implementations of the same service.
|
In Angular, dependencies are typically services, but can also be values, such as strings or functions.
|
||||||
|
An [injector](guide/glossary#injector) for an app (created automatically during bootstrap) instantiates dependencies when needed, using a configured [provider](guide/glossary#provider) of the service or value.
|
||||||
|
|
||||||
Learn more in the [Dependency Injection](guide/dependency-injection) guide.
|
Learn more in the [Dependency Injection](guide/dependency-injection) guide.
|
||||||
|
|
||||||
@ -280,7 +285,7 @@ Compare [Custom element](guide/glossary#custom-element).
|
|||||||
|
|
||||||
## Entry point
|
## Entry point
|
||||||
|
|
||||||
A JavaScript ID that makes parts of an NPM package available for import by other code.
|
A JavaScript symbol that makes parts of an npm package available for import by other code.
|
||||||
The Angular [scoped packages](guide/glossary#scoped-package) each have an entry point named `index`.
|
The Angular [scoped packages](guide/glossary#scoped-package) each have an entry point named `index`.
|
||||||
|
|
||||||
Within Angular, use [NgModules](guide/glossary#ngmodule) to achieve the same result.
|
Within Angular, use [NgModules](guide/glossary#ngmodule) to achieve the same result.
|
||||||
@ -310,7 +315,17 @@ Both a [service](guide/glossary#service) and a [component](guide/glossary#compon
|
|||||||
|
|
||||||
An object in the Angular [dependency-injection system](guide/glossary#dependency-injection)
|
An object in the Angular [dependency-injection system](guide/glossary#dependency-injection)
|
||||||
that can find a named dependency in its cache or create a dependency
|
that can find a named dependency in its cache or create a dependency
|
||||||
with a registered [provider](guide/glossary#provider). Injectors are created for NgModules automatically as part of the bootstrap process, and inherited through the component hierarchy.
|
using a configured [provider](guide/glossary#provider).
|
||||||
|
Injectors are created for NgModules automatically as part of the bootstrap process
|
||||||
|
and are inherited through the component hierarchy.
|
||||||
|
|
||||||
|
* An injector provides a singleton instance of a dependency, and can inject this same instance in multiple components.
|
||||||
|
|
||||||
|
* A hierarchy of injectors at the NgModule and component level can provide different instances of a dependency to their own components and child components.
|
||||||
|
|
||||||
|
* You can configure injectors with different providers that can provide different implementations of the same dependency.
|
||||||
|
|
||||||
|
Learn more about the injector hierarchy in the [Dependency Injection guide](guide/hierarchical-dependency-injection).
|
||||||
|
|
||||||
|
|
||||||
## Input
|
## Input
|
||||||
@ -373,6 +388,17 @@ Lazy loading speeds up application load time by splitting the application into m
|
|||||||
For example, dependencies can be lazy-loaded as needed&emdash;as opposed to "eager-loaded" modules that are required by the root module, and are thus loaded on launch.
|
For example, dependencies can be lazy-loaded as needed&emdash;as opposed to "eager-loaded" modules that are required by the root module, and are thus loaded on launch.
|
||||||
Similarly, the [router](guide/glossary#router) can load child views only when the parent view is activated, and you can build custom elements that can be loaded into an Angular app when needed.
|
Similarly, the [router](guide/glossary#router) can load child views only when the parent view is activated, and you can build custom elements that can be loaded into an Angular app when needed.
|
||||||
|
|
||||||
|
{@a library}
|
||||||
|
|
||||||
|
## Library
|
||||||
|
|
||||||
|
In Angular, a [project](guide/glossary#project) that provides functionality that can be included in other Angular apps. A library is not a complete Angular app, and it cannot run independently.
|
||||||
|
|
||||||
|
* Library developers can use the [CLI](guide/glossary#cli) to `generate` scaffolding for a new library in an existing [workspace](guide/glossary#workspace), and can publish a library as an `npm` package.
|
||||||
|
|
||||||
|
* App developers can use the [CLI](guide/glossary#cli) to `add` a published library for use with an app in the same [workspace](guide/glossary#workspace).
|
||||||
|
|
||||||
|
|
||||||
## Lifecycle hook
|
## Lifecycle hook
|
||||||
|
|
||||||
An interface that allows you to tap into the lifecycle of [directives](guide/glossary#directive) and [components](guide/glossary#component) as they are created, updated, and destroyed.
|
An interface that allows you to tap into the lifecycle of [directives](guide/glossary#directive) and [components](guide/glossary#component) as they are created, updated, and destroyed.
|
||||||
@ -402,7 +428,7 @@ In general, a module collects a block of code dedicated to a single purpose. Ang
|
|||||||
|
|
||||||
In JavaScript (ECMAScript), each file is a module and all objects defined in the file belong to that module. Objects can exported, making them public, and public objects can be imported for use by other modules.
|
In JavaScript (ECMAScript), each file is a module and all objects defined in the file belong to that module. Objects can exported, making them public, and public objects can be imported for use by other modules.
|
||||||
|
|
||||||
Angular ships as a collection of JavaScript modules, or libraries. Each Angular library name begins with the `@angular` prefix. Install them with the NPM package manager and import parts of them with JavaScript `import` declarations.
|
Angular ships as a collection of JavaScript modules, or libraries. Each Angular library name begins with the `@angular` prefix. Install them with the npm package manager and import parts of them with JavaScript `import` declarations.
|
||||||
|
|
||||||
Compare the Angular [NgModule](guide/glossary#ngmodule).
|
Compare the Angular [NgModule](guide/glossary#ngmodule).
|
||||||
|
|
||||||
@ -439,7 +465,7 @@ Observables can deliver single or multiple values of any type to subscribers, ei
|
|||||||
|
|
||||||
Angular uses a third-party library called [Reactive Extensions (RxJS)](http://reactivex.io/rxjs/).
|
Angular uses a third-party library called [Reactive Extensions (RxJS)](http://reactivex.io/rxjs/).
|
||||||
|
|
||||||
To learn more, see the [Observables](guide/glossary#observable) guide.
|
To learn more, see the [Observables](guide/observables) guide.
|
||||||
|
|
||||||
|
|
||||||
{@a observer}
|
{@a observer}
|
||||||
@ -470,8 +496,13 @@ To learn more, see the [pipes](guide/pipes) page.
|
|||||||
|
|
||||||
## Polyfill
|
## Polyfill
|
||||||
|
|
||||||
An [NPM package](guide/npm-packages) that plugs gaps in a browser's JavaScript implementation. See the [Browser Support](guide/browser-support) guide for polyfills that support particular functionality for particular platforms.
|
An [npm package](guide/npm-packages) that plugs gaps in a browser's JavaScript implementation. See the [Browser Support](guide/browser-support) guide for polyfills that support particular functionality for particular platforms.
|
||||||
|
|
||||||
|
{@a project}
|
||||||
|
|
||||||
|
## Project
|
||||||
|
|
||||||
|
In Angular, a folder within a [workspace](guide/glossary#workspace) that contains an Angular app or [library](guide/glossary#library). A workspace can contain multiple projects. All apps in a workspace can use libraries in the same workspace.
|
||||||
|
|
||||||
## Provider
|
## Provider
|
||||||
|
|
||||||
@ -531,9 +562,24 @@ For more information, see the [Routing & Navigation](guide/router) page.
|
|||||||
|
|
||||||
{@a S}
|
{@a S}
|
||||||
|
|
||||||
|
{@a schematic}
|
||||||
|
|
||||||
|
## Schematic
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
* Angular provides a set of schematics for use with the CLI.
|
||||||
|
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.
|
||||||
|
For more information, see https://www.npmjs.com/package/@angular-devkit/schematics.
|
||||||
|
|
||||||
|
|
||||||
## Scoped package
|
## Scoped package
|
||||||
|
|
||||||
A way to group related NPM packages.
|
A way to group related npm packages.
|
||||||
NgModules are delivered within *scoped packages* whose names begin with the Angular *scope name* `@angular`. For example, `@angular/core`, `@angular/common`, `@angular/http`, and `@angular/router`.
|
NgModules are delivered within *scoped packages* whose names begin with the Angular *scope name* `@angular`. For example, `@angular/core`, `@angular/common`, `@angular/http`, and `@angular/router`.
|
||||||
|
|
||||||
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.
|
||||||
@ -677,6 +723,12 @@ The view hierarchy does not imply a component hierarchy. Views that are embedded
|
|||||||
|
|
||||||
See [Custom element](guide/glossary#custom-element)
|
See [Custom element](guide/glossary#custom-element)
|
||||||
|
|
||||||
|
{@a workspace}
|
||||||
|
|
||||||
|
## Workspace
|
||||||
|
|
||||||
|
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. Commands such as `add` and `generate`, that create or operate on apps and libraries, must be executed from within a workspace folder.
|
||||||
|
|
||||||
{@a X}
|
{@a X}
|
||||||
|
|
||||||
|
@ -450,7 +450,7 @@ Here is a `searchHeroes` method that queries for heroes whose names contain the
|
|||||||
|
|
||||||
If there is a search term, the code constructs an options object with an HTML URL-encoded search parameter. If the term were "foo", the GET request URL would be `api/heroes/?name=foo`.
|
If there is a search term, the code constructs an options object with an HTML URL-encoded search parameter. If the term were "foo", the GET request URL would be `api/heroes/?name=foo`.
|
||||||
|
|
||||||
The `HttpParms` are immutable so you'll have to use the `set()` method to update the options.
|
The `HttpParams` are immutable so you'll have to use the `set()` method to update the options.
|
||||||
|
|
||||||
### Debouncing requests
|
### Debouncing requests
|
||||||
|
|
||||||
|
@ -74,9 +74,8 @@ Here's the dev dependency
|
|||||||
you need to have in `package.json`:
|
you need to have in `package.json`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|
||||||
devDependencies {
|
devDependencies {
|
||||||
"@angular/language-service": "^4.0.0"
|
"@angular/language-service": "^6.0.0"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ configure services in root and feature modules respectively.
|
|||||||
|
|
||||||
Angular doesn't recognize these names but Angular developers do.
|
Angular doesn't recognize these names but Angular developers do.
|
||||||
Follow this convention when you write similar modules with configurable service providers.
|
Follow this convention when you write similar modules with configurable service providers.
|
||||||
<!--KW--I don't understand how Angular doesn't understand these methods...-->
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
@ -233,9 +233,8 @@ When you import an NgModule,
|
|||||||
Angular adds the module's service providers (the contents of its `providers` list)
|
Angular adds the module's service providers (the contents of its `providers` list)
|
||||||
to the application root injector.
|
to the application root injector.
|
||||||
|
|
||||||
This makes the provider visible to every class in the application that knows the provider's lookup token, or knows its name.
|
This makes the provider visible to every class in the application that knows the provider's lookup token, or name.
|
||||||
|
|
||||||
This is by design.
|
|
||||||
Extensibility through NgModule imports is a primary goal of the NgModule system.
|
Extensibility through NgModule imports is a primary goal of the NgModule system.
|
||||||
Merging NgModule providers into the application injector
|
Merging NgModule providers into the application injector
|
||||||
makes it easy for a module library to enrich the entire application with new services.
|
makes it easy for a module library to enrich the entire application with new services.
|
||||||
@ -247,6 +246,8 @@ If the `HeroModule` provides the `HeroService` and the root `AppModule` imports
|
|||||||
any class that knows the `HeroService` _type_ can inject that service,
|
any class that knows the `HeroService` _type_ can inject that service,
|
||||||
not just the classes declared in the `HeroModule`.
|
not just the classes declared in the `HeroModule`.
|
||||||
|
|
||||||
|
To limit access to a service, consider lazy loading the NgModule that provides that service. See [How do I restrict service scope to a module?](guide/ngmodule-faq#service-scope) for more information.
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
{@a q-lazy-loaded-module-provider-visibility}
|
{@a q-lazy-loaded-module-provider-visibility}
|
||||||
@ -288,6 +289,7 @@ The `AppModule` always wins.
|
|||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
|
{@a service-scope}
|
||||||
|
|
||||||
## How do I restrict service scope to a module?
|
## How do I restrict service scope to a module?
|
||||||
|
|
||||||
@ -335,6 +337,8 @@ You can embed the child components in the top component's template.
|
|||||||
Alternatively, make the top component a routing host by giving it a `<router-outlet>`.
|
Alternatively, make the top component a routing host by giving it a `<router-outlet>`.
|
||||||
Define child routes and let the router load module components into that outlet.
|
Define child routes and let the router load module components into that outlet.
|
||||||
|
|
||||||
|
Though you can limit access to a service by providing it in a lazy loaded module or providing it in a component, providing services in a component can lead to multiple instances of those services. Thus, the lazy loading is preferable.
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
{@a q-root-component-or-module}
|
{@a q-root-component-or-module}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
Every application starts out with what seems like a simple task: get data, transform them, and show them to users.
|
Every application starts out with what seems like a simple task: get data, transform them, and show them to users.
|
||||||
Getting data could be as simple as creating a local variable or as complex as streaming data over a WebSocket.
|
Getting data could be as simple as creating a local variable or as complex as streaming data over a WebSocket.
|
||||||
|
|
||||||
Once data arrive, you could push their raw `toString` values directly to the view,
|
Once data arrives, you could push their raw `toString` values directly to the view,
|
||||||
but that rarely makes for a good user experience.
|
but that rarely makes for a good user experience.
|
||||||
For example, in most use cases, users prefer to see a date in a simple format like
|
For example, in most use cases, users prefer to see a date in a simple format like
|
||||||
<samp>April 15, 1988</samp> rather than the raw string format
|
<samp>April 15, 1988</samp> rather than the raw string format
|
||||||
|
@ -74,22 +74,58 @@ The following table contains our current target release dates for the next two m
|
|||||||
|
|
||||||
|
|
||||||
{@a lts}
|
{@a lts}
|
||||||
## Long-term support
|
{@a support}
|
||||||
|
## Support policy
|
||||||
|
|
||||||
All of our releases are supported actively for about 6 months (until the next major release), and then they are supported through long-term support (LTS) for another 12 months.
|
All of our major releases are supported for 18 months.
|
||||||
|
|
||||||
During the LTS period, only critical fixes and security patches will be merged and released.
|
* 6 months of active support, during which regularly-scheduled updates and patches are released, as described above in [Release frequency](#frequency "Release frequency").
|
||||||
|
|
||||||
The LTS state of one major version starts on the day of the next major release. LTS status ends approximately one year later, when we release another major version.
|
* 12 months of long-term support (LTS). During the LTS period, only critical fixes and security patches will be released.
|
||||||
|
|
||||||
|
The following table provides the support status and key dates for Angular version 4.0.0 and higher.
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
Version | LTS Start Date | LTS End Date
|
td, th {vertical-align: top}
|
||||||
----------- | -------------- | ------------
|
|
||||||
^4.0.0 | October 2017 | October 2018
|
|
||||||
^5.0.0 | April 2018 | April 2019
|
|
||||||
^6.0.0 | October 2018 | October 2019
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -106,7 +142,7 @@ To make these transitions as easy as possible, we make two commitments to you:
|
|||||||
|
|
||||||
To help ensure that you have sufficient time and a clear path to update, this is our deprecation policy:
|
To help ensure that you have sufficient time and a clear path to update, this is our deprecation policy:
|
||||||
|
|
||||||
* When announce deprecated features in the [change log](https://github.com/angular/angular/blob/master/CHANGELOG.md "Angular change log").
|
* We announce deprecated features in the [change log](https://github.com/angular/angular/blob/master/CHANGELOG.md "Angular change log").
|
||||||
|
|
||||||
* When we announce a deprecation, we also announce a recommended update path.
|
* When we announce a deprecation, we also announce a recommended update path.
|
||||||
|
|
||||||
@ -129,6 +165,4 @@ Any changes to the public API surface will be done using the versioning, support
|
|||||||
|
|
||||||
Angular Labs is an initiative to cultivate new features and iterate on them quickly. Angular Labs provides a safe place for exploration and experimentation by the Angular team.
|
Angular Labs is an initiative to cultivate new features and iterate on them quickly. Angular Labs provides a safe place for exploration and experimentation by the Angular team.
|
||||||
|
|
||||||
Angular Labs projects are are not ready for production use, and no commitment is made to bring them to production. The policies and practices that are described in this document do not apply to Angular Labs projects.
|
Angular Labs projects are not ready for production use, and no commitment is made to bring them to production. The policies and practices that are described in this document do not apply to Angular Labs projects.
|
||||||
|
|
||||||
Angular Labs projects typically are in separate branches in the Angular repo, clearly separated from the main Angular codebase.
|
|
||||||
|
@ -3656,7 +3656,7 @@ Lazy loading has multiple benefits.
|
|||||||
* You can speed up load time for users that only visit certain areas of the application.
|
* You can speed up load time for users that only visit certain areas of the application.
|
||||||
* You can continue expanding lazy loaded feature areas without increasing the size of the initial load bundle.
|
* You can continue expanding lazy loaded feature areas without increasing the size of the initial load bundle.
|
||||||
|
|
||||||
You're already made part way there.
|
You're already part of the way there.
|
||||||
By organizing the application into modules—`AppModule`,
|
By organizing the application into modules—`AppModule`,
|
||||||
`HeroesModule`, `AdminModule` and `CrisisCenterModule`—you
|
`HeroesModule`, `AdminModule` and `CrisisCenterModule`—you
|
||||||
have natural candidates for lazy loading.
|
have natural candidates for lazy loading.
|
||||||
|
@ -70,6 +70,7 @@ interface AssetGroup {
|
|||||||
updateMode?: 'prefetch' | 'lazy';
|
updateMode?: 'prefetch' | 'lazy';
|
||||||
resources: {
|
resources: {
|
||||||
files?: string[];
|
files?: string[];
|
||||||
|
/** @deprecated As of v6 `versionedFiles` and `files` options have the same behavior. Use `files` instead. */
|
||||||
versionedFiles?: string[];
|
versionedFiles?: string[];
|
||||||
urls?: string[];
|
urls?: string[];
|
||||||
};
|
};
|
||||||
@ -102,7 +103,7 @@ This section describes the resources to cache, broken up into three groups.
|
|||||||
|
|
||||||
* `files` lists patterns that match files in the distribution directory. These can be single files or glob-like patterns that match a number of files.
|
* `files` lists patterns that match files in the distribution directory. These can be single files or glob-like patterns that match a number of files.
|
||||||
|
|
||||||
* `versionedFiles` is like `files` but should be used for build artifacts that already include a hash in the filename, which is used for cache busting. The Angular service worker can optimize some aspects of its operation if it can assume file contents are immutable.
|
* `versionedFiles` has been deprecated. As of v6 `versionedFiles` and `files` options have the same behavior. Use `files` instead.
|
||||||
|
|
||||||
* `urls` includes both URLs and URL patterns that will be matched at runtime. These resources are not fetched directly and do not have content hashes, but they will be cached according to their HTTP headers. This is most useful for CDNs such as the Google Fonts service.<br>
|
* `urls` includes both URLs and URL patterns that will be matched at runtime. These resources are not fetched directly and do not have content hashes, but they will be cached according to their HTTP headers. This is most useful for CDNs such as the Google Fonts service.<br>
|
||||||
_(Negative glob patterns are not supported.)_
|
_(Negative glob patterns are not supported.)_
|
||||||
|
@ -933,29 +933,18 @@ As always, strive for consistency.
|
|||||||
|
|
||||||
<a href="#toc">Back to top</a>
|
<a href="#toc">Back to top</a>
|
||||||
|
|
||||||
{@a 02-06}
|
{@a 05-02}
|
||||||
|
|
||||||
### Directive selectors
|
### Component selectors
|
||||||
|
|
||||||
#### Style 02-06
|
#### Style 05-02
|
||||||
|
|
||||||
|
|
||||||
<div class="s-rule do">
|
<div class="s-rule do">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Do** Use lower camel case for naming the selectors of directives.
|
**Do** use _dashed-case_ or _kebab-case_ for naming the element selectors of components.
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="s-why">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Why?** Keeps the names of the properties defined in the directives that are bound to the view consistent with the attribute names.
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -966,16 +955,40 @@ As always, strive for consistency.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Why?** The Angular HTML parser is case sensitive and recognizes lower camel case.
|
**Why?** Keeps the element names consistent with the specification for [Custom Elements](https://www.w3.org/TR/custom-elements/).
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<code-example path="styleguide/src/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/shared/hero-button/hero-button.component.ts">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<code-tabs>
|
||||||
|
|
||||||
|
<code-pane title="app/heroes/shared/hero-button/hero-button.component.ts" path="styleguide/src/05-02/app/heroes/shared/hero-button/hero-button.component.ts" region="example">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
<code-pane title="app/app.component.html" path="styleguide/src/05-02/app/app.component.html">
|
||||||
|
|
||||||
|
</code-pane>
|
||||||
|
|
||||||
|
</code-tabs>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="#toc">Back to top</a>
|
<a href="#toc">Back to top</a>
|
||||||
|
|
||||||
{@a 02-07}
|
{@a 02-07}
|
||||||
|
|
||||||
### Custom prefix for components
|
### Component custom prefix
|
||||||
|
|
||||||
#### Style 02-07
|
#### Style 02-07
|
||||||
|
|
||||||
@ -1078,11 +1091,51 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a href="#toc">Back to top</a>
|
||||||
|
|
||||||
|
{@a 02-06}
|
||||||
|
|
||||||
|
### Directive selectors
|
||||||
|
|
||||||
|
#### Style 02-06
|
||||||
|
|
||||||
|
|
||||||
|
<div class="s-rule do">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Do** Use lower camel case for naming the selectors of directives.
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="s-why">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Why?** Keeps the names of the properties defined in the directives that are bound to the view consistent with the attribute names.
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="s-why-last">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Why?** The Angular HTML parser is case sensitive and recognizes lower camel case.
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="#toc">Back to top</a>
|
||||||
|
|
||||||
{@a 02-08}
|
{@a 02-08}
|
||||||
|
|
||||||
### Custom prefix for directives
|
### Directive custom prefix
|
||||||
|
|
||||||
#### Style 02-08
|
#### Style 02-08
|
||||||
|
|
||||||
@ -3056,9 +3109,9 @@ module are referenced across the entire application.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Avoid** providing services in shared modules. Services are usually
|
**Consider** _not_ providing services in shared modules. Services are usually
|
||||||
singletons that are provided once for the entire application or
|
singletons that are provided once for the entire application or
|
||||||
in a particular feature module.
|
in a particular feature module. There are exceptions, however. For example, in the sample code that follows, notice that the `SharedModule` provides `FilterTextService`. This is acceptable here because the service is stateless;that is, the consumers of the service aren't impacted by new instances.
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -3710,59 +3763,6 @@ A typical *lazy loaded folder* contains a *routing component*, its child compone
|
|||||||
|
|
||||||
## Components
|
## Components
|
||||||
|
|
||||||
{@a 05-02}
|
|
||||||
|
|
||||||
### Component selector names
|
|
||||||
|
|
||||||
#### Style 05-02
|
|
||||||
|
|
||||||
|
|
||||||
<div class="s-rule do">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Do** use _dashed-case_ or _kebab-case_ for naming the element selectors of components.
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="s-why-last">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Why?** Keeps the element names consistent with the specification for [Custom Elements](https://www.w3.org/TR/custom-elements/).
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<code-example path="styleguide/src/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/shared/hero-button/hero-button.component.ts">
|
|
||||||
|
|
||||||
</code-example>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<code-tabs>
|
|
||||||
|
|
||||||
<code-pane title="app/heroes/shared/hero-button/hero-button.component.ts" path="styleguide/src/05-02/app/heroes/shared/hero-button/hero-button.component.ts" region="example">
|
|
||||||
|
|
||||||
</code-pane>
|
|
||||||
|
|
||||||
<code-pane title="app/app.component.html" path="styleguide/src/05-02/app/app.component.html">
|
|
||||||
|
|
||||||
</code-pane>
|
|
||||||
|
|
||||||
</code-tabs>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="#toc">Back to top</a>
|
|
||||||
|
|
||||||
{@a 05-03}
|
{@a 05-03}
|
||||||
|
|
||||||
### Components as elements
|
### Components as elements
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user