Compare commits
275 Commits
4.3.0
...
patch_sync
Author | SHA1 | Date | |
---|---|---|---|
f2f5286020 | |||
47220997e1 | |||
9ffa490d3f | |||
a80ecf6a77 | |||
7236095f6f | |||
d1c4a94bbf | |||
d76761bf01 | |||
c055dc7441 | |||
3dc4115c8b | |||
1f1caacbfd | |||
713d7c2360 | |||
079d884b6c | |||
a73389bc71 | |||
33d250ffaa | |||
409688fe17 | |||
ec56760c9b | |||
7ce9e06dab | |||
8ea6c56fe1 | |||
c0ba2b9ca7 | |||
fc7c858e62 | |||
55d151a82d | |||
5a1b9a34df | |||
70628112e8 | |||
29aa8b33df | |||
e25f05ae7c | |||
791c7efe29 | |||
2159342038 | |||
e228f2caa6 | |||
7522987a51 | |||
ff6a20d138 | |||
4eb1f91bee | |||
f53f7241a0 | |||
f2a2a6b478 | |||
d61b9021e0 | |||
499d05ddee | |||
b8a3736275 | |||
7d72d0eb9b | |||
7f4c964eef | |||
be9713c6e2 | |||
596e9f4e04 | |||
da14391cff | |||
60c803649b | |||
17b71ae382 | |||
a56468cf2f | |||
d7f42bfbe6 | |||
8f413268cf | |||
2a62d9f056 | |||
5f5a8e1da6 | |||
6e3498ca8e | |||
7bfd850493 | |||
ffb1553282 | |||
56a5b02d04 | |||
0cc77b4a69 | |||
a0ca01d580 | |||
2da45e629d | |||
845c68fdb3 | |||
21c44672c4 | |||
83713ddea4 | |||
3a500981ef | |||
0d45828460 | |||
43226cb93d | |||
2572bf508f | |||
6a1ab61cce | |||
27d5058e01 | |||
9aa05211ff | |||
40d69c317c | |||
bc22ff1517 | |||
75d484e29d | |||
32ff21c16b | |||
c65f18a2fa | |||
697c6ed0fe | |||
0a73e8d062 | |||
64b4be9670 | |||
77747e10c0 | |||
1cfa79ca4e | |||
cce2ab2625 | |||
38addacda0 | |||
3efd4a15d6 | |||
96b57bfcc1 | |||
a93dece069 | |||
14d8186bf6 | |||
856278cfea | |||
5e840e1e79 | |||
233ef93e88 | |||
9320f34f19 | |||
d2c0d986d4 | |||
088532bf2e | |||
27d901a51d | |||
cac130eff9 | |||
679608db65 | |||
06faac8b5c | |||
4d523fda98 | |||
cea02414b0 | |||
f0ec31e47f | |||
ff5c58be6b | |||
dca50deae4 | |||
7f2037f0b6 | |||
fd6ae571b8 | |||
b14250bef9 | |||
6fb5250185 | |||
2f9d8ff46d | |||
e54bd59f22 | |||
1e1833198d | |||
6f2038cc85 | |||
f0a55016af | |||
fcadbf4bf6 | |||
d9d00bd9b5 | |||
f69561b2de | |||
685cc26ab2 | |||
5b7432b6ea | |||
04b18a9f46 | |||
05472cb21b | |||
c0c03dc4ba | |||
f9f8924c49 | |||
10897d6473 | |||
340837aa46 | |||
42ef1be75c | |||
a5801b6020 | |||
70b62949de | |||
36161d99f6 | |||
0714139e37 | |||
bcb36d9b6d | |||
ca695e0632 | |||
9b015a95eb | |||
939dc44391 | |||
5651e4ac72 | |||
1dca575701 | |||
333a708bb6 | |||
3a227a1f6f | |||
81cb5bc3a7 | |||
1640d2aa0b | |||
5f501c722b | |||
ea07856cc5 | |||
7c47b62a96 | |||
e25b3dd163 | |||
6a88659c9a | |||
44ae6e94e3 | |||
1635a06bda | |||
3923c30df0 | |||
99017bf3ff | |||
4d117faf1a | |||
5cc9913ded | |||
1d09838622 | |||
9adf40aa77 | |||
89c616199f | |||
1e1af7ffcb | |||
a84b2bc945 | |||
7abcb99d57 | |||
49cd8513e4 | |||
82b067fc40 | |||
9479a106bb | |||
e64b54b67b | |||
cc2a4c41f9 | |||
a11542a375 | |||
b6c4af6495 | |||
67dff7bd5d | |||
381471d338 | |||
ebef5e697a | |||
d71ae278ef | |||
46207538ef | |||
71eb7437b6 | |||
b5ffbe342b | |||
0f79223008 | |||
a085223331 | |||
c383048259 | |||
b18eb04b46 | |||
c8c2ab012a | |||
ecff8e6c93 | |||
51f1da1b85 | |||
a5e18c4cdf | |||
cf6284656f | |||
3182ddaf3e | |||
416ed691e5 | |||
0fb7484d51 | |||
6a3454e81e | |||
c3fbe87012 | |||
24117d7a49 | |||
5808153359 | |||
9030c8a03e | |||
b14fc06fa2 | |||
a7f2468184 | |||
fae47d86b3 | |||
d20ac14fe2 | |||
cae3e6dca0 | |||
086f4aa72c | |||
82923a381d | |||
5152abb037 | |||
67f7032321 | |||
205abe8140 | |||
b582e2b311 | |||
91ab39cc55 | |||
38ec05f533 | |||
b3085e96c2 | |||
4cea2bd612 | |||
ce47546188 | |||
6279e50d78 | |||
8bcb268140 | |||
6fc5940959 | |||
0317c4c478 | |||
b7a6f52d59 | |||
7ae7573bc8 | |||
abee785821 | |||
619e625ee2 | |||
a6c635e69e | |||
e0a9625e46 | |||
fd0cc01eed | |||
1bfc77bf8c | |||
a094769bca | |||
b4c98305da | |||
a3a54299af | |||
15a3e2d307 | |||
54e0244954 | |||
43c33d5663 | |||
6d7799fce9 | |||
d31dc7b2b3 | |||
4cd4f7a208 | |||
72fe45db2b | |||
8d2819121b | |||
073e8ba2f2 | |||
5d1864fe68 | |||
eaa843b55f | |||
c6cf678a07 | |||
31cb418370 | |||
8de44cf5e3 | |||
c67bad4f43 | |||
410f21c75c | |||
54ea5b6ffd | |||
0af03beaed | |||
d71fa734f5 | |||
6f45519d6f | |||
65c9e13105 | |||
9208f0beea | |||
5344be5182 | |||
5db6f38b73 | |||
d22f8f54db | |||
23146c9201 | |||
a5205c686e | |||
807648251f | |||
5c62e300e1 | |||
256bc8acdd | |||
59c23c7bd7 | |||
e03adb9edd | |||
b399cb26d9 | |||
3b588fe2b0 | |||
95635c18c7 | |||
e20cfe1bbc | |||
eb6fb5f87e | |||
ad3029e786 | |||
2a2fe11e8d | |||
7d0f2cd51e | |||
36faba1aab | |||
92179bcc64 | |||
cdb069ab0e | |||
c453b7bcfa | |||
9d97163c64 | |||
f054c8360b | |||
758848961e | |||
99b666614d | |||
3f331b53b2 | |||
375d598a9f | |||
cd67fced1c | |||
a77cf7ee37 | |||
2150b45954 | |||
9f99f4fae2 | |||
c6ad212a98 | |||
47b3ecd9a3 | |||
8c81c62d46 | |||
7e72317059 | |||
0bb8423df9 | |||
95698d93ad | |||
c649da9f0a | |||
0bf0c35bca | |||
97e6901ded | |||
30e76fcd80 | |||
44b50427d9 |
@ -41,8 +41,8 @@ jobs:
|
||||
- restore_cache:
|
||||
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}
|
||||
|
||||
- run: bazel run @io_bazel_rules_typescript_node//:bin/npm install
|
||||
- run: bazel build ...
|
||||
- run: bazel run @nodejs//:npm install
|
||||
- run: bazel build packages/...
|
||||
- save_cache:
|
||||
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}
|
||||
paths:
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,6 +5,7 @@ bazel-*
|
||||
e2e_test.*
|
||||
node_modules
|
||||
bower_components
|
||||
tools/gulp-tasks/cldr/cldr-data/
|
||||
|
||||
# Include when developing application packages.
|
||||
pubspec.lock
|
||||
|
@ -69,7 +69,6 @@ groups:
|
||||
- "*.lock"
|
||||
- "tools/*"
|
||||
exclude:
|
||||
- "tools/@angular/tsc-wrapped/*"
|
||||
- "tools/public_api_guard/*"
|
||||
- "aio/*"
|
||||
users:
|
||||
@ -136,8 +135,9 @@ groups:
|
||||
compiler-cli:
|
||||
conditions:
|
||||
files:
|
||||
- "tools/@angular/tsc-wrapped/*"
|
||||
- "packages/tsc-wrapped/*"
|
||||
- "packages/compiler-cli/*"
|
||||
- "packages/bazel/*"
|
||||
users:
|
||||
- alexeagle
|
||||
- chuckjaz
|
||||
@ -256,6 +256,8 @@ groups:
|
||||
files:
|
||||
include:
|
||||
- "aio/*"
|
||||
exclude:
|
||||
- "aio/content/*"
|
||||
users:
|
||||
- petebacondarwin #primary
|
||||
- IgorMinar
|
||||
@ -276,6 +278,8 @@ groups:
|
||||
- Foxandxss
|
||||
- stephenfluin
|
||||
- wardbell
|
||||
- petebacondarwin
|
||||
- gkalpak
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
||||
@ -289,5 +293,7 @@ groups:
|
||||
users:
|
||||
- juleskremer #primary
|
||||
- stephenfluin
|
||||
- petebacondarwin
|
||||
- gkalpak
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
10
.travis.yml
10
.travis.yml
@ -1,9 +1,12 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
# force trusty as Google Chrome addon is not supported on Precise
|
||||
dist: trusty
|
||||
node_js:
|
||||
- '6.9.5'
|
||||
|
||||
addons:
|
||||
chrome: stable
|
||||
# firefox: "38.0"
|
||||
apt:
|
||||
sources:
|
||||
@ -50,16 +53,17 @@ env:
|
||||
- CI_MODE=browserstack_required
|
||||
- CI_MODE=saucelabs_optional
|
||||
- CI_MODE=browserstack_optional
|
||||
- CI_MODE=docs_test
|
||||
- CI_MODE=aio_tools_test
|
||||
- CI_MODE=aio
|
||||
- CI_MODE=aio_e2e
|
||||
- CI_MODE=aio_e2e AIO_SHARD=0
|
||||
- CI_MODE=aio_e2e AIO_SHARD=1
|
||||
- CI_MODE=bazel
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: "CI_MODE=saucelabs_optional"
|
||||
- env: "CI_MODE=browserstack_optional"
|
||||
- env: "CI_MODE=aio_e2e"
|
||||
|
||||
before_install:
|
||||
# source the env.sh script so that the exported variables are available to other scripts later on
|
||||
|
@ -11,8 +11,15 @@ filegroup(
|
||||
# This won't scale in the general case.
|
||||
# TODO(alexeagle): figure out what to do
|
||||
"node_modules/typescript/**",
|
||||
"node_modules/zone.js/**/*.d.ts",
|
||||
"node_modules/zone.js/**",
|
||||
"node_modules/rxjs/**/*.d.ts",
|
||||
"node_modules/rxjs/**/*.js",
|
||||
"node_modules/@types/**/*.d.ts",
|
||||
"node_modules/tsickle/**",
|
||||
"node_modules/hammerjs/**/*.d.ts",
|
||||
"node_modules/protobufjs/**",
|
||||
"node_modules/bytebuffer/**",
|
||||
"node_modules/reflect-metadata/**",
|
||||
"node_modules/minimist/**/*.js",
|
||||
]),
|
||||
)
|
244
CHANGELOG.md
244
CHANGELOG.md
@ -1,3 +1,247 @@
|
||||
<a name="5.0.0-beta.4"></a>
|
||||
# [5.0.0-beta.4](https://github.com/angular/angular/compare/5.0.0-beta.3...5.0.0-beta.4) (2017-08-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **aio:** fix compilation error by using the correct type for `providers` ([4d523fd](https://github.com/angular/angular/commit/4d523fd))
|
||||
* **aio:** skip PWA test when redeploying non-public commit ([06faac8](https://github.com/angular/angular/commit/06faac8))
|
||||
* **compiler:** Don't strip CSS source maps ([64b4be9](https://github.com/angular/angular/commit/64b4be9))
|
||||
* **forms:** re-assigning options should not clear select ([32ff21c](https://github.com/angular/angular/commit/32ff21c)), closes [#18330](https://github.com/angular/angular/issues/18330)
|
||||
* **language-service:** remove tsickle dependency ([bc22ff1](https://github.com/angular/angular/commit/bc22ff1))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **common:** mark NgTemplateOutlet API as stable ([0a73e8d](https://github.com/angular/angular/commit/0a73e8d))
|
||||
* **forms:** add status to `AbstractControlDirective` ([233ef93](https://github.com/angular/angular/commit/233ef93))
|
||||
* **forms:** add updateOn support to ngModelOptions ([1cfa79c](https://github.com/angular/angular/commit/1cfa79c))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **aio:** update to new version of build-optimizer ([088532b](https://github.com/angular/angular/commit/088532b))
|
||||
* **core:** add option to remove blank text nodes from compiled templates ([d2c0d98](https://github.com/angular/angular/commit/d2c0d98))
|
||||
* **core:** Remove decorator DSL which depends on Reflect ([cac130e](https://github.com/angular/angular/commit/cac130e))
|
||||
|
||||
|
||||
|
||||
<a name="4.3.5"></a>
|
||||
## [4.3.5](https://github.com/angular/angular/compare/4.3.4...4.3.5) (2017-08-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **aio:** skip PWA test when redeploying non-public commit ([b9c1c91](https://github.com/angular/angular/commit/b9c1c91))
|
||||
* **core:** forbid destroyed views to be inserted or moved in VC ([972538b](https://github.com/angular/angular/commit/972538b)), closes [#18615](https://github.com/angular/angular/issues/18615)
|
||||
* **forms:** re-assigning options should not clear select ([a1624f2](https://github.com/angular/angular/commit/a1624f2)), closes [#18330](https://github.com/angular/angular/issues/18330)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **aio:** update to new version of build-optimizer ([d7be4f1](https://github.com/angular/angular/commit/d7be4f1))
|
||||
|
||||
|
||||
|
||||
<a name="4.3.4"></a>
|
||||
## [4.3.4](https://github.com/angular/angular/compare/4.3.3...4.3.4) (2017-08-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animations:** revert container/queried animations accordingly during cancel ([#18516](https://github.com/angular/angular/issues/18516)) ([5a165eb](https://github.com/angular/angular/commit/5a165eb))
|
||||
* **animations:** support persisting dynamic styles within animation states ([#18468](https://github.com/angular/angular/issues/18468)) ([e0660b1](https://github.com/angular/angular/commit/e0660b1)), closes [#18423](https://github.com/angular/angular/issues/18423) [#17505](https://github.com/angular/angular/issues/17505)
|
||||
* **benchpress:** compile cleanly with TS 2.4 ([#18455](https://github.com/angular/angular/issues/18455)) ([5afc7ab](https://github.com/angular/angular/commit/5afc7ab))
|
||||
* **compiler:** cleanly compile with TypeScript 2.4 ([#18456](https://github.com/angular/angular/issues/18456)) ([5e4054b](https://github.com/angular/angular/commit/5e4054b))
|
||||
* **compiler:** ignore [@import](https://github.com/import) in multi-line css ([#18452](https://github.com/angular/angular/issues/18452)) ([e7e7622](https://github.com/angular/angular/commit/e7e7622)), closes [#18038](https://github.com/angular/angular/issues/18038)
|
||||
|
||||
|
||||
<a name="5.0.0-beta.3"></a>
|
||||
# [5.0.0-beta.3](https://github.com/angular/angular/compare/5.0.0-beta.2...5.0.0-beta.3) (2017-08-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animations:** revert container/queried animations accordingly during cancel ([#18516](https://github.com/angular/angular/issues/18516)) ([c0c03dc](https://github.com/angular/angular/commit/c0c03dc))
|
||||
* **animations:** support persisting dynamic styles within animation states ([#18468](https://github.com/angular/angular/issues/18468)) ([05472cb](https://github.com/angular/angular/commit/05472cb)), closes [#18423](https://github.com/angular/angular/issues/18423) [#17505](https://github.com/angular/angular/issues/17505)
|
||||
* **benchpress:** compile cleanly with TS 2.4 ([#18455](https://github.com/angular/angular/issues/18455)) ([e25b3dd](https://github.com/angular/angular/commit/e25b3dd))
|
||||
* **common:** don't recreate view when context shape doesn't change ([#18277](https://github.com/angular/angular/issues/18277)) ([685cc26](https://github.com/angular/angular/commit/685cc26)), closes [#13407](https://github.com/angular/angular/issues/13407)
|
||||
* **compiler:** cleanly compile with TypeScript 2.4 ([#18456](https://github.com/angular/angular/issues/18456)) ([7c47b62](https://github.com/angular/angular/commit/7c47b62))
|
||||
* **compiler:** ignore [@import](https://github.com/import) in multi-line css ([#18452](https://github.com/angular/angular/issues/18452)) ([1dca575](https://github.com/angular/angular/commit/1dca575)), closes [#18038](https://github.com/angular/angular/issues/18038)
|
||||
* **compiler-cli:** disable buggy expression lowering ([#18513](https://github.com/angular/angular/issues/18513)) ([ca695e0](https://github.com/angular/angular/commit/ca695e0))
|
||||
* **compiler-cli:** fix and re-enable expression lowering ([#18570](https://github.com/angular/angular/issues/18570)) ([6f2038c](https://github.com/angular/angular/commit/6f2038c)), closes [#18388](https://github.com/angular/angular/issues/18388)
|
||||
* **compiler-cli:** modified ngc to throw all errors, not just syntax ([#18388](https://github.com/angular/angular/issues/18388)) ([5651e4a](https://github.com/angular/angular/commit/5651e4a))
|
||||
* **compiler-cli:** remove minimist dependency of compiler-cli/index ([#18532](https://github.com/angular/angular/issues/18532)) ([5b7432b](https://github.com/angular/angular/commit/5b7432b))
|
||||
* **core:** fix platform-browser-dynamic ([#18576](https://github.com/angular/angular/issues/18576)) ([f0a5501](https://github.com/angular/angular/commit/f0a5501))
|
||||
* **core:** forbid destroyed views to be inserted or moved in VC ([#18568](https://github.com/angular/angular/issues/18568)) ([e54bd59](https://github.com/angular/angular/commit/e54bd59)), closes [#17780](https://github.com/angular/angular/issues/17780)
|
||||
|
||||
### Features
|
||||
|
||||
* **core:** Create StaticInjector which does not depend on Reflect polyfill. ([d9d00bd](https://github.com/angular/angular/commit/d9d00bd))
|
||||
* **forms:** add default updateOn values for groups and arrays ([#18536](https://github.com/angular/angular/issues/18536)) ([ff5c58b](https://github.com/angular/angular/commit/ff5c58b))
|
||||
* **forms:** add updateOn blur option to FormControls ([#18408](https://github.com/angular/angular/issues/18408)) ([333a708](https://github.com/angular/angular/commit/333a708)), closes [#7113](https://github.com/angular/angular/issues/7113)
|
||||
* **forms:** add updateOn submit option to FormControls ([#18514](https://github.com/angular/angular/issues/18514)) ([f69561b](https://github.com/angular/angular/commit/f69561b))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* switch angular to use StaticInjector instead of ReflectiveInjector ([fcadbf4](https://github.com/angular/angular/commit/fcadbf4)), closes [#18496](https://github.com/angular/angular/issues/18496)
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* `platformXXXX()` no longer accepts providers which depend on reflection.
|
||||
Specifically the method signature when from `Provider[]` to
|
||||
`StaticProvider[]`.
|
||||
|
||||
Example:
|
||||
Before:
|
||||
```
|
||||
[
|
||||
MyClass,
|
||||
{provide: ClassA, useClass: SubClassA}
|
||||
]
|
||||
|
||||
```
|
||||
|
||||
After:
|
||||
```
|
||||
[
|
||||
{provide: MyClass, deps: [Dep1,...]},
|
||||
{provide: ClassA, useClass: SubClassA, deps: [Dep1,...]}
|
||||
]
|
||||
```
|
||||
|
||||
NOTE: This only applies to platform creation and providers for the JIT
|
||||
compiler. It does not apply to `@Component` or `@NgModule` provides
|
||||
declarations.
|
||||
|
||||
Benchpress note: Previously Benchpress also supported reflective
|
||||
provides, which now require static providers.
|
||||
|
||||
DEPRECATION:
|
||||
|
||||
- `ReflectiveInjector` is now deprecated as it will be remove. Use
|
||||
`Injector.create` as a replacement.
|
||||
|
||||
<a name="5.0.0-beta.2"></a>
|
||||
# [5.0.0-beta.2](https://github.com/angular/angular/compare/5.0.0-beta.1...5.0.0-beta.2) (2017-08-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler:** do not consider arguments when determining recursion ([e64b54b](https://github.com/angular/angular/commit/e64b54b))
|
||||
* **compiler:** fix for element needing implicit parent placed in top-level ng-container ([381471d](https://github.com/angular/angular/commit/381471d)), closes [#18314](https://github.com/angular/angular/issues/18314)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **forms:** add options arg to abstract controls ([ebef5e6](https://github.com/angular/angular/commit/ebef5e6))
|
||||
* **router:** add events tracking activation of individual routes ([49cd851](https://github.com/angular/angular/commit/49cd851))
|
||||
|
||||
|
||||
<a name="4.3.3"></a>
|
||||
## [4.3.3](https://github.com/angular/angular/compare/4.3.2...4.3.3) (2017-08-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler:** fix for element needing implicit parent placed in top-level ng-container ([f5cbc2e](https://github.com/angular/angular/commit/f5cbc2e)), closes [#18314](https://github.com/angular/angular/issues/18314)
|
||||
|
||||
|
||||
<a name="5.0.0-beta.1"></a>
|
||||
# [5.0.0-beta.1](https://github.com/angular/angular/compare/5.0.0-beta.0...5.0.0-beta.1) (2017-07-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animations:** export BrowserModule as apart of BrowserAnimationsModule ([#18263](https://github.com/angular/angular/issues/18263)) ([fd0cc01](https://github.com/angular/angular/commit/fd0cc01))
|
||||
* **compiler:** add equiv & disp attributes to Xliff2 ICU placeholders ([#18283](https://github.com/angular/angular/issues/18283)) ([38ec05f](https://github.com/angular/angular/commit/38ec05f)), closes [#17344](https://github.com/angular/angular/issues/17344)
|
||||
* **compiler:** allow numbers for ICU message cases in lexer ([#18095](https://github.com/angular/angular/issues/18095)) ([a3a5429](https://github.com/angular/angular/commit/a3a5429)), closes [#17799](https://github.com/angular/angular/issues/17799)
|
||||
* **core:** invoke error handler outside of the Angular Zone ([#18269](https://github.com/angular/angular/issues/18269)) ([7ae7573](https://github.com/angular/angular/commit/7ae7573)), closes [#17073](https://github.com/angular/angular/issues/17073) [#7774](https://github.com/angular/angular/issues/7774)
|
||||
* **platform-server:** don't clobber parse5 properties when setting ([#18237](https://github.com/angular/angular/issues/18237)) ([a094769](https://github.com/angular/angular/commit/a094769)), closes [#17050](https://github.com/angular/angular/issues/17050)
|
||||
* **router:** child CanActivate guard should wait for parent to complete ([#18110](https://github.com/angular/angular/issues/18110)) ([086f4aa](https://github.com/angular/angular/commit/086f4aa)), closes [#15670](https://github.com/angular/angular/issues/15670)
|
||||
* **router:** should throw when lazy loaded module doesn't define any routes ([#15001](https://github.com/angular/angular/issues/15001)) ([82923a3](https://github.com/angular/angular/commit/82923a3)), closes [#14596](https://github.com/angular/angular/issues/14596)
|
||||
* **upgrade:** ensure downgraded components are created in the Angular zone ([#18209](https://github.com/angular/angular/issues/18209)) ([43c33d5](https://github.com/angular/angular/commit/43c33d5))
|
||||
* **upgrade:** throw error if trying to get injector before setting ([#18209](https://github.com/angular/angular/issues/18209)) ([d31dc7b](https://github.com/angular/angular/commit/d31dc7b))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compiler:** add representation of placeholders to xliff & xmb ([b3085e9](https://github.com/angular/angular/commit/b3085e9)), closes [#17345](https://github.com/angular/angular/issues/17345)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* latest tsickle to tree shake: abstract class methods & interfaces ([#18236](https://github.com/angular/angular/issues/18236)) ([b7a6f52](https://github.com/angular/angular/commit/b7a6f52))
|
||||
* **core:** use native addEventListener for faster rendering. ([#18107](https://github.com/angular/angular/issues/18107)) ([6279e50](https://github.com/angular/angular/commit/6279e50))
|
||||
|
||||
|
||||
|
||||
<a name="4.3.2"></a>
|
||||
## [4.3.2](https://github.com/angular/angular/compare/4.3.1...4.3.2) (2017-07-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animations:** export BrowserModule as apart of BrowserAnimationsModule ([#18263](https://github.com/angular/angular/issues/18263)) ([cbeb197](https://github.com/angular/angular/commit/cbeb197))
|
||||
* **compiler:** add equiv & disp attributes to Xliff2 ICU placeholders ([#18283](https://github.com/angular/angular/issues/18283)) ([a084619](https://github.com/angular/angular/commit/a084619)), closes [#17344](https://github.com/angular/angular/issues/17344)
|
||||
* **compiler:** allow numbers for ICU message cases in lexer ([#18095](https://github.com/angular/angular/issues/18095)) ([a8ac77b](https://github.com/angular/angular/commit/a8ac77b)), closes [#17799](https://github.com/angular/angular/issues/17799)
|
||||
* **core:** invoke error handler outside of the Angular Zone ([#18269](https://github.com/angular/angular/issues/18269)) ([a1bb9c2](https://github.com/angular/angular/commit/a1bb9c2)), closes [#17073](https://github.com/angular/angular/issues/17073) [#7774](https://github.com/angular/angular/issues/7774)
|
||||
* **platform-server:** don't clobber parse5 properties when setting ([#18237](https://github.com/angular/angular/issues/18237)) ([97135e8](https://github.com/angular/angular/commit/97135e8)), closes [#17050](https://github.com/angular/angular/issues/17050)
|
||||
* **router:** child CanActivate guard should wait for parent to complete ([#18110](https://github.com/angular/angular/issues/18110)) ([b9e32c8](https://github.com/angular/angular/commit/b9e32c8)), closes [#15670](https://github.com/angular/angular/issues/15670)
|
||||
* **router:** should throw when lazy loaded module doesn't define any routes ([#15001](https://github.com/angular/angular/issues/15001)) ([be49e0e](https://github.com/angular/angular/commit/be49e0e)), closes [#14596](https://github.com/angular/angular/issues/14596)
|
||||
* **upgrade:** throw error if trying to get injector before setting ([#18209](https://github.com/angular/angular/issues/18209)) ([1f106d7](https://github.com/angular/angular/commit/1f106d7))
|
||||
|
||||
|
||||
|
||||
<a name="5.0.0-beta.0"></a>
|
||||
# [5.0.0-beta.0](https://github.com/angular/angular/compare/4.3.0...5.0.0-beta.0) (2017-07-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animations:** always camelcase style property names that contain auto styles ([d22f8f5](https://github.com/angular/angular/commit/d22f8f5)), closes [#17938](https://github.com/angular/angular/issues/17938)
|
||||
* **animations:** capture cancelled animation styles within grouped animations ([23146c9](https://github.com/angular/angular/commit/23146c9)), closes [#17170](https://github.com/angular/angular/issues/17170)
|
||||
* **animations:** do not crash animations if a nested component fires CD during CD ([5db6f38](https://github.com/angular/angular/commit/5db6f38)), closes [#18193](https://github.com/angular/angular/issues/18193)
|
||||
* **animations:** make sure @.disabled works in non-animation components ([5344be5](https://github.com/angular/angular/commit/5344be5))
|
||||
* **common:** send flushed body as error instead of null ([5c62e30](https://github.com/angular/angular/commit/5c62e30)), closes [#18181](https://github.com/angular/angular/issues/18181)
|
||||
* **compiler:** ensure jit external id arguments names are unique ([95635c1](https://github.com/angular/angular/commit/95635c1))
|
||||
* **compiler-cli:** don't generate empty <target/> when extracting xliff ([65c9e13](https://github.com/angular/angular/commit/65c9e13)), closes [#15754](https://github.com/angular/angular/issues/15754)
|
||||
* **platform-server:** provide XhrFactory for HttpClient ([8076482](https://github.com/angular/angular/commit/8076482))
|
||||
* **router:** canDeactivate guards should run from bottom to top ([e20cfe1](https://github.com/angular/angular/commit/e20cfe1)), closes [#15657](https://github.com/angular/angular/issues/15657)
|
||||
* **router:** should navigate to the same url when config changes ([eb6fb5f](https://github.com/angular/angular/commit/eb6fb5f)), closes [#15535](https://github.com/angular/angular/issues/15535)
|
||||
* **router:** should run resolvers for the same route concurrently ([ad3029e](https://github.com/angular/angular/commit/ad3029e)), closes [#14279](https://github.com/angular/angular/issues/14279)
|
||||
* **router:** terminal route in custom matcher ([b399cb2](https://github.com/angular/angular/commit/b399cb2))
|
||||
* **upgrade:** allow accessing AngularJS injector from downgraded module ([a5205c6](https://github.com/angular/angular/commit/a5205c6))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **animations:** support :increment and :decrement transition aliases ([6f45519](https://github.com/angular/angular/commit/6f45519))
|
||||
* **upgrade:** propagate touched state of NgModelController ([59c23c7](https://github.com/angular/angular/commit/59c23c7))
|
||||
* **upgrade:** support lazy-loading Angular module into AngularJS app ([30e76fc](https://github.com/angular/angular/commit/30e76fc))
|
||||
|
||||
|
||||
|
||||
<a name="4.3.1"></a>
|
||||
## [4.3.1](https://github.com/angular/angular/compare/4.3.0...4.3.1) (2017-07-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animations:** always camelcase style property names that contain auto styles ([383d896](https://github.com/angular/angular/commit/383d896)), closes [#17938](https://github.com/angular/angular/issues/17938)
|
||||
* **animations:** capture cancelled animation styles within grouped animations ([333ffd8](https://github.com/angular/angular/commit/333ffd8)), closes [#17170](https://github.com/angular/angular/issues/17170)
|
||||
* **animations:** do not crash animations if a nested component fires CD during CD ([4c1f32b](https://github.com/angular/angular/commit/4c1f32b)), closes [#18193](https://github.com/angular/angular/issues/18193)
|
||||
* **animations:** make sure @.disabled works in non-animation components ([a5c4bb5](https://github.com/angular/angular/commit/a5c4bb5))
|
||||
* **common:** send flushed body as error instead of null ([17b7bc3](https://github.com/angular/angular/commit/17b7bc3)), closes [#18181](https://github.com/angular/angular/issues/18181)
|
||||
* **compiler:** ensure jit external id arguments names are unique ([4671168](https://github.com/angular/angular/commit/4671168))
|
||||
* **compiler-cli:** don't generate empty `<target/>` when extracting xliff ([f0476fc](https://github.com/angular/angular/commit/f0476fc)), closes [#15754](https://github.com/angular/angular/issues/15754)
|
||||
* **platform-server:** provide XhrFactory for HttpClient ([4ce29f3](https://github.com/angular/angular/commit/4ce29f3))
|
||||
* **router:** canDeactivate guards should run from bottom to top ([1ac78bf](https://github.com/angular/angular/commit/1ac78bf)), closes [#15657](https://github.com/angular/angular/issues/15657)
|
||||
* **router:** should navigate to the same url when config changes ([4340bea](https://github.com/angular/angular/commit/4340bea)), closes [#15535](https://github.com/angular/angular/issues/15535)
|
||||
* **router:** should run resolvers for the same route concurrently ([ec89f37](https://github.com/angular/angular/commit/ec89f37)), closes [#14279](https://github.com/angular/angular/issues/14279)
|
||||
* **router:** terminal route in custom matcher ([5d275e9](https://github.com/angular/angular/commit/5d275e9))
|
||||
|
||||
|
||||
|
||||
<a name="4.3.0"></a>
|
||||
# [4.3.0](https://github.com/angular/angular/compare/4.3.0-rc.0...4.3.0) (2017-07-14)
|
||||
|
||||
|
20
WORKSPACE
20
WORKSPACE
@ -1,11 +1,21 @@
|
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
|
||||
git_repository(
|
||||
name = "io_bazel_rules_typescript",
|
||||
remote = "https://github.com/bazelbuild/rules_typescript.git",
|
||||
commit = "3a8404d",
|
||||
name = "build_bazel_rules_nodejs",
|
||||
remote = "https://github.com/bazelbuild/rules_nodejs.git",
|
||||
tag = "0.0.2",
|
||||
)
|
||||
|
||||
load("@io_bazel_rules_typescript//:defs.bzl", "node_repositories")
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")
|
||||
|
||||
node_repositories(package_json = "//:package.json")
|
||||
node_repositories(package_json = ["//:package.json"])
|
||||
|
||||
local_repository(
|
||||
name = "build_bazel_rules_typescript",
|
||||
path = "node_modules/@bazel/typescript",
|
||||
)
|
||||
|
||||
local_repository(
|
||||
name = "angular",
|
||||
path = "packages/bazel",
|
||||
)
|
@ -31,8 +31,9 @@
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"stage": "environments/environment.stage.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
"next": "environments/environment.next.ts",
|
||||
"stable": "environments/environment.stable.ts",
|
||||
"archive": "environments/environment.archive.ts"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -26,7 +26,7 @@ Here are the most important tasks you might need to use:
|
||||
* `yarn docs-lint` - check that the doc gen code follows our style rules.
|
||||
* `yarn docs-test` - run the unit tests for the doc generation code.
|
||||
|
||||
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally.
|
||||
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally. Add the option `-- --local` to use your local version of Angular contained in the "dist" folder.
|
||||
* `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`.
|
||||
* `yarn generate-plunkers` - generate the plunker files that are used by the `live-example` tags in the docs.
|
||||
* `yarn generate-zips` - generate the zip files from the examples. Zip available via the `live-example` tags in the docs.
|
||||
@ -34,6 +34,7 @@ Here are the most important tasks you might need to use:
|
||||
* `yarn example-e2e` - run all e2e tests for examples
|
||||
- `yarn example-e2e -- --setup` - force webdriver update & other setup, then run tests
|
||||
- `yarn example-e2e -- --filter=foo` - limit e2e tests to those containing the word "foo"
|
||||
- `yarn example-e2e -- --setup --local` - run e2e tests with the local version of Angular contained in the "dist" folder
|
||||
|
||||
* `yarn build-ie-polyfills` - generates a js file of polyfills that can be loaded in Internet Explorer.
|
||||
|
||||
|
@ -32,7 +32,8 @@ export class BuildCreator extends EventEmitter {
|
||||
then(() => Promise.all([this.exists(prDir), this.exists(shaDir)])).
|
||||
then(([prDirExisted, shaDirExisted]) => {
|
||||
if (shaDirExisted) {
|
||||
throw new UploadError(409, `Request to overwrite existing directory: ${shaDir}`);
|
||||
const publicOrNot = isPublic ? 'public' : 'non-public';
|
||||
throw new UploadError(409, `Request to overwrite existing ${publicOrNot} directory: ${shaDir}`);
|
||||
}
|
||||
|
||||
dirToRemoveOnError = prDirExisted ? shaDir : prDir;
|
||||
|
@ -110,6 +110,7 @@ describe('upload-server (on HTTP)', () => {
|
||||
const authorizationHeader2 = isPublic ?
|
||||
authorizationHeader : `--header "Authorization: ${c.BV_verify_verifiedNotTrusted}"`;
|
||||
const cmdPrefix = curl('', `${authorizationHeader2} ${xFileHeader}`);
|
||||
const overwriteRe = RegExp(`^Request to overwrite existing ${isPublic ? 'public' : 'non-public'} directory`);
|
||||
|
||||
|
||||
it('should not overwrite existing builds', done => {
|
||||
@ -120,7 +121,7 @@ describe('upload-server (on HTTP)', () => {
|
||||
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toBe('My content');
|
||||
|
||||
h.runCmd(`${cmdPrefix} http://${host}/create-build/${pr}/${sha9}`).
|
||||
then(h.verifyResponse(409, /^Request to overwrite existing directory/)).
|
||||
then(h.verifyResponse(409, overwriteRe)).
|
||||
then(() => expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toBe('My content')).
|
||||
then(done);
|
||||
});
|
||||
@ -141,7 +142,7 @@ describe('upload-server (on HTTP)', () => {
|
||||
expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toBe('My content');
|
||||
|
||||
h.runCmd(`${cmdPrefix} http://${host}/create-build/${pr}/${sha9Almost}`).
|
||||
then(h.verifyResponse(409, /^Request to overwrite existing directory/)).
|
||||
then(h.verifyResponse(409, overwriteRe)).
|
||||
then(() => expect(h.readBuildFile(pr, sha9, 'index.html', isPublic)).toBe('My content')).
|
||||
then(done);
|
||||
});
|
||||
@ -310,7 +311,7 @@ describe('upload-server (on HTTP)', () => {
|
||||
expect(h.buildExists(pr, sha0, isPublic)).toBe(false);
|
||||
|
||||
uploadBuild(sha0).
|
||||
then(h.verifyResponse(409, /^Request to overwrite existing directory/)).
|
||||
then(h.verifyResponse(409, overwriteRe)).
|
||||
then(() => {
|
||||
checkPrVisibility(isPublic);
|
||||
expect(h.readBuildFile(pr, sha0, 'index.html', isPublic)).toContain(pr);
|
||||
|
@ -153,7 +153,8 @@ describe('BuildCreator', () => {
|
||||
it('should abort and skip further operations if the build does already exist', done => {
|
||||
existsValues[shaDir] = true;
|
||||
bc.create(pr, sha, archive, isPublic).catch(err => {
|
||||
expectToBeUploadError(err, 409, `Request to overwrite existing directory: ${shaDir}`);
|
||||
const publicOrNot = isPublic ? 'public' : 'non-public';
|
||||
expectToBeUploadError(err, 409, `Request to overwrite existing ${publicOrNot} directory: ${shaDir}`);
|
||||
expect(shellMkdirSpy).not.toHaveBeenCalled();
|
||||
expect(bcExtractArchiveSpy).not.toHaveBeenCalled();
|
||||
expect(bcEmitSpy).not.toHaveBeenCalled();
|
||||
@ -169,7 +170,8 @@ describe('BuildCreator', () => {
|
||||
expect(bcExistsSpy(shaDir)).toBe(false);
|
||||
|
||||
bc.create(pr, sha, archive, isPublic).catch(err => {
|
||||
expectToBeUploadError(err, 409, `Request to overwrite existing directory: ${shaDir}`);
|
||||
const publicOrNot = isPublic ? 'public' : 'non-public';
|
||||
expectToBeUploadError(err, 409, `Request to overwrite existing ${publicOrNot} directory: ${shaDir}`);
|
||||
expect(shellMkdirSpy).not.toHaveBeenCalled();
|
||||
expect(bcExtractArchiveSpy).not.toHaveBeenCalled();
|
||||
expect(bcEmitSpy).not.toHaveBeenCalled();
|
||||
|
@ -6,7 +6,7 @@
|
||||
"interface-name": [true, "never-prefix"],
|
||||
"max-classes-per-file": [true, 4],
|
||||
"no-consecutive-blank-lines": [true, 2],
|
||||
"no-console": false,
|
||||
"no-console": [false],
|
||||
"no-namespace": [true, "allow-declarations"],
|
||||
"no-string-literal": false,
|
||||
"quotemark": [true, "single"],
|
||||
|
@ -46,8 +46,8 @@ with a bried explanation of what they mean:
|
||||
Request method other than POST.
|
||||
|
||||
- **409 (Conflict)**:
|
||||
Request to overwrite existing directory (e.g. deploy existing build or change PR visibility when
|
||||
the destination directory does already exist).
|
||||
Request to overwrite existing (public or non-public) directory (e.g. deploy existing build or
|
||||
change PR visibility when the destination directory does already exist).
|
||||
|
||||
- **413 (Payload Too Large)**:
|
||||
Payload larger than size specified in `AIO_UPLOAD_MAX_SIZE`.
|
||||
@ -71,7 +71,8 @@ with a bried explanation of what they mean:
|
||||
Request method other than POST.
|
||||
|
||||
- **409 (Conflict)**:
|
||||
Request to overwrite existing directory (i.e. directories for both visibilities exist).
|
||||
Request to overwrite existing (public or non-public) directory (i.e. directories for both
|
||||
visibilities exist).
|
||||
(Normally, this should not happen.)
|
||||
|
||||
|
||||
|
14
aio/content/examples/.gitignore
vendored
14
aio/content/examples/.gitignore
vendored
@ -43,13 +43,9 @@ dist/
|
||||
**/app/**/*.ajs.js
|
||||
|
||||
# aot
|
||||
**/*.ngfactory.ts
|
||||
**/*.ngsummary.json
|
||||
**/*.ngsummary.ts
|
||||
**/*.shim.ngstyle.ts
|
||||
**/*.metadata.json
|
||||
!aot/bs-config.json
|
||||
!aot/index.html
|
||||
*/aot/**/*
|
||||
!*/aot/bs-config.json
|
||||
!*/aot/index.html
|
||||
!rollup-config.js
|
||||
|
||||
# i18n
|
||||
@ -59,10 +55,6 @@ dist/
|
||||
!testing/src/browser-test-shim.js
|
||||
!testing/karma*.js
|
||||
|
||||
# TS to JS
|
||||
!ts-to-js/js*/**/*.js
|
||||
ts-to-js/js*/**/system*.js
|
||||
|
||||
# webpack
|
||||
!webpack/**/config/*.js
|
||||
!webpack/**/*webpack*.js
|
||||
|
@ -9,30 +9,20 @@ describe('Form Validation Tests', function () {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
describe('Hero Form 1', () => {
|
||||
describe('Template-driven form', () => {
|
||||
beforeAll(() => {
|
||||
getPage('hero-form-template1');
|
||||
getPage('hero-form-template');
|
||||
});
|
||||
|
||||
tests();
|
||||
tests('Template-Driven Form');
|
||||
});
|
||||
|
||||
describe('Hero Form 2', () => {
|
||||
describe('Reactive form', () => {
|
||||
beforeAll(() => {
|
||||
getPage('hero-form-template2');
|
||||
getPage('hero-form-reactive');
|
||||
});
|
||||
|
||||
tests();
|
||||
bobTests();
|
||||
});
|
||||
|
||||
describe('Hero Form 3 (Reactive)', () => {
|
||||
beforeAll(() => {
|
||||
getPage('hero-form-reactive3');
|
||||
makeNameTooLong();
|
||||
});
|
||||
|
||||
tests();
|
||||
tests('Reactive Form');
|
||||
bobTests();
|
||||
});
|
||||
});
|
||||
@ -48,6 +38,7 @@ let page: {
|
||||
nameInput: ElementFinder,
|
||||
alterEgoInput: ElementFinder,
|
||||
powerSelect: ElementFinder,
|
||||
powerOption: ElementFinder,
|
||||
errorMessages: ElementArrayFinder,
|
||||
heroFormButtons: ElementArrayFinder,
|
||||
heroSubmitted: ElementFinder
|
||||
@ -64,19 +55,21 @@ function getPage(sectionTag: string) {
|
||||
nameInput: section.element(by.css('#name')),
|
||||
alterEgoInput: section.element(by.css('#alterEgo')),
|
||||
powerSelect: section.element(by.css('#power')),
|
||||
powerOption: section.element(by.css('#power option')),
|
||||
errorMessages: section.all(by.css('div.alert')),
|
||||
heroFormButtons: buttons,
|
||||
heroSubmitted: section.element(by.css('hero-submitted > div'))
|
||||
heroSubmitted: section.element(by.css('.submitted-message'))
|
||||
};
|
||||
}
|
||||
|
||||
function tests() {
|
||||
function tests(title: string) {
|
||||
|
||||
it('should display correct title', function () {
|
||||
expect(page.title.getText()).toContain('Hero Form');
|
||||
expect(page.title.getText()).toContain(title);
|
||||
});
|
||||
|
||||
it('should not display submitted message before submit', function () {
|
||||
expect(page.heroSubmitted.isElementPresent(by.css('h2'))).toBe(false);
|
||||
expect(page.heroSubmitted.isElementPresent(by.css('p'))).toBe(false);
|
||||
});
|
||||
|
||||
it('should have form buttons', function () {
|
||||
@ -130,11 +123,11 @@ function tests() {
|
||||
|
||||
it('should hide form after submit', function () {
|
||||
page.heroFormButtons.get(0).click();
|
||||
expect(page.title.isDisplayed()).toBe(false);
|
||||
expect(page.heroFormButtons.get(0).isDisplayed()).toBe(false);
|
||||
});
|
||||
|
||||
it('submitted form should be displayed', function () {
|
||||
expect(page.heroSubmitted.isElementPresent(by.css('h2'))).toBe(true);
|
||||
expect(page.heroSubmitted.isElementPresent(by.css('p'))).toBe(true);
|
||||
});
|
||||
|
||||
it('submitted form should have new hero name', function () {
|
||||
@ -142,9 +135,9 @@ function tests() {
|
||||
});
|
||||
|
||||
it('clicking edit button should reveal form again', function () {
|
||||
const editBtn = page.heroSubmitted.element(by.css('button'));
|
||||
editBtn.click();
|
||||
expect(page.heroSubmitted.isElementPresent(by.css('h2')))
|
||||
const newFormBtn = page.heroSubmitted.element(by.css('button'));
|
||||
newFormBtn.click();
|
||||
expect(page.heroSubmitted.isElementPresent(by.css('p')))
|
||||
.toBe(false, 'submitted hidden again');
|
||||
expect(page.title.isDisplayed()).toBe(true, 'can see form title');
|
||||
});
|
||||
@ -159,9 +152,13 @@ function expectFormIsInvalid() {
|
||||
}
|
||||
|
||||
function bobTests() {
|
||||
const emsg = 'Someone named "Bob" cannot be a hero.';
|
||||
const emsg = 'Name cannot be Bob.';
|
||||
|
||||
it('should produce "no bob" error after setting name to "Bobby"', function () {
|
||||
// Re-populate select element
|
||||
page.powerSelect.click();
|
||||
page.powerOption.click();
|
||||
|
||||
page.nameInput.clear();
|
||||
page.nameInput.sendKeys('Bobby');
|
||||
expectFormIsInvalid();
|
||||
@ -174,8 +171,3 @@ function bobTests() {
|
||||
expectFormIsValid();
|
||||
});
|
||||
}
|
||||
|
||||
function makeNameTooLong() {
|
||||
// make the first name invalid
|
||||
page.nameInput.sendKeys('ThisHeroNameHasWayWayTooManyLetters');
|
||||
}
|
||||
|
@ -3,10 +3,8 @@ import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
template: `<hero-form-template1></hero-form-template1>
|
||||
template: `<hero-form-template></hero-form-template>
|
||||
<hr>
|
||||
<hero-form-template2></hero-form-template2>
|
||||
<hr>
|
||||
<hero-form-reactive3></hero-form-reactive3>`
|
||||
<hero-form-reactive></hero-form-reactive>`
|
||||
})
|
||||
export class AppComponent { }
|
||||
|
@ -1,18 +1,26 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { HeroFormTemplateModule } from './template/hero-form-template.module';
|
||||
import { HeroFormReactiveModule } from './reactive/hero-form-reactive.module';
|
||||
import { HeroFormTemplateComponent } from './template/hero-form-template.component';
|
||||
import { HeroFormReactiveComponent } from './reactive/hero-form-reactive.component';
|
||||
import { ForbiddenValidatorDirective } from './shared/forbidden-name.directive';
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
HeroFormTemplateModule,
|
||||
HeroFormReactiveModule
|
||||
FormsModule,
|
||||
ReactiveFormsModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
HeroFormTemplateComponent,
|
||||
HeroFormReactiveComponent,
|
||||
ForbiddenValidatorDirective
|
||||
],
|
||||
declarations: [ AppComponent ],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
@ -1,26 +1,38 @@
|
||||
<!-- #docregion -->
|
||||
<div class="container">
|
||||
<div [hidden]="submitted">
|
||||
<h1>Hero Form 3 (Reactive)</h1>
|
||||
<!-- #docregion form-tag-->
|
||||
<form [formGroup]="heroForm" *ngIf="active" (ngSubmit)="onSubmit()">
|
||||
<!-- #enddocregion form-tag-->
|
||||
<div class="form-group">
|
||||
<!-- #docregion name-with-error-msg -->
|
||||
<label for="name">Name</label>
|
||||
|
||||
<input type="text" id="name" class="form-control"
|
||||
<h1>Reactive Form</h1>
|
||||
|
||||
<form [formGroup]="heroForm" #formDir="ngForm">
|
||||
|
||||
<div [hidden]="formDir.submitted">
|
||||
|
||||
<div class="form-group">
|
||||
|
||||
<label for="name">Name</label>
|
||||
<!-- #docregion name-with-error-msg -->
|
||||
<input id="name" class="form-control"
|
||||
formControlName="name" required >
|
||||
|
||||
<div *ngIf="formErrors.name" class="alert alert-danger">
|
||||
{{ formErrors.name }}
|
||||
<div *ngIf="name.invalid && (name.dirty || name.touched)"
|
||||
class="alert alert-danger">
|
||||
|
||||
<div *ngIf="name.errors.required">
|
||||
Name is required.
|
||||
</div>
|
||||
<div *ngIf="name.errors.minlength">
|
||||
Name must be at least 4 characters long.
|
||||
</div>
|
||||
<div *ngIf="name.errors.forbiddenName">
|
||||
Name cannot be Bob.
|
||||
</div>
|
||||
</div>
|
||||
<!-- #enddocregion name-with-error-msg -->
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input type="text" id="alterEgo" class="form-control"
|
||||
<input id="alterEgo" class="form-control"
|
||||
formControlName="alterEgo" >
|
||||
</div>
|
||||
|
||||
@ -31,17 +43,20 @@
|
||||
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
|
||||
<div *ngIf="formErrors.power" class="alert alert-danger">
|
||||
{{ formErrors.power }}
|
||||
<div *ngIf="power.invalid && power.touched" class="alert alert-danger">
|
||||
<div *ngIf="power.errors.required">Power is required.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-default"
|
||||
[disabled]="!heroForm.valid">Submit</button>
|
||||
[disabled]="heroForm.invalid">Submit</button>
|
||||
<button type="button" class="btn btn-default"
|
||||
(click)="addHero()">New Hero</button>
|
||||
</form>
|
||||
</div>
|
||||
(click)="formDir.resetForm({})">Reset</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<hero-submitted [hero]="hero" [(submitted)]="submitted"></hero-submitted>
|
||||
<div class="submitted-message" *ngIf="formDir.submitted">
|
||||
<p>You've submitted your hero, {{ heroForm.value.name }}!</p>
|
||||
<button (click)="formDir.resetForm({})">Add new hero</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,115 +2,39 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
import { Hero } from '../shared/hero';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { forbiddenNameValidator } from '../shared/forbidden-name.directive';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-form-reactive3',
|
||||
selector: 'hero-form-reactive',
|
||||
templateUrl: './hero-form-reactive.component.html'
|
||||
})
|
||||
export class HeroFormReactiveComponent implements OnInit {
|
||||
|
||||
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
|
||||
|
||||
hero = new Hero(18, 'Dr. WhatIsHisName', this.powers[0], 'Dr. What');
|
||||
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
|
||||
|
||||
submitted = false;
|
||||
|
||||
// #docregion on-submit
|
||||
onSubmit() {
|
||||
this.submitted = true;
|
||||
this.hero = this.heroForm.value;
|
||||
}
|
||||
// #enddocregion on-submit
|
||||
// #enddocregion
|
||||
|
||||
// Reset the form with a new hero AND restore 'pristine' class state
|
||||
// by toggling 'active' flag which causes the form
|
||||
// to be removed/re-added in a tick via NgIf
|
||||
// TODO: Workaround until NgForm has a reset method (#6822)
|
||||
active = true;
|
||||
// #docregion class
|
||||
// #docregion add-hero
|
||||
addHero() {
|
||||
this.hero = new Hero(42, '', '');
|
||||
this.buildForm();
|
||||
// #enddocregion add-hero
|
||||
// #enddocregion class
|
||||
|
||||
this.active = false;
|
||||
setTimeout(() => this.active = true, 0);
|
||||
// #docregion
|
||||
// #docregion add-hero
|
||||
}
|
||||
// #enddocregion add-hero
|
||||
|
||||
// #docregion form-builder
|
||||
heroForm: FormGroup;
|
||||
constructor(private fb: FormBuilder) { }
|
||||
|
||||
// #docregion form-group
|
||||
ngOnInit(): void {
|
||||
this.buildForm();
|
||||
}
|
||||
|
||||
buildForm(): void {
|
||||
this.heroForm = this.fb.group({
|
||||
// #docregion name-validators
|
||||
'name': [this.hero.name, [
|
||||
Validators.required,
|
||||
Validators.minLength(4),
|
||||
Validators.maxLength(24),
|
||||
forbiddenNameValidator(/bob/i)
|
||||
]
|
||||
],
|
||||
// #enddocregion name-validators
|
||||
'alterEgo': [this.hero.alterEgo],
|
||||
'power': [this.hero.power, Validators.required]
|
||||
// #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)
|
||||
});
|
||||
|
||||
this.heroForm.valueChanges
|
||||
.subscribe(data => this.onValueChanged(data));
|
||||
|
||||
this.onValueChanged(); // (re)set validation messages now
|
||||
// #enddocregion custom-validator
|
||||
}
|
||||
|
||||
// #enddocregion form-builder
|
||||
get name() { return this.heroForm.get('name'); }
|
||||
|
||||
onValueChanged(data?: any) {
|
||||
if (!this.heroForm) { return; }
|
||||
const form = this.heroForm;
|
||||
|
||||
for (const field in this.formErrors) {
|
||||
// clear previous error message (if any)
|
||||
this.formErrors[field] = '';
|
||||
const control = form.get(field);
|
||||
|
||||
if (control && control.dirty && !control.valid) {
|
||||
const messages = this.validationMessages[field];
|
||||
for (const key in control.errors) {
|
||||
this.formErrors[field] += messages[key] + ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
formErrors = {
|
||||
'name': '',
|
||||
'power': ''
|
||||
};
|
||||
|
||||
validationMessages = {
|
||||
'name': {
|
||||
'required': 'Name is required.',
|
||||
'minlength': 'Name must be at least 4 characters long.',
|
||||
'maxlength': 'Name cannot be more than 24 characters long.',
|
||||
'forbiddenName': 'Someone named "Bob" cannot be a hero.'
|
||||
},
|
||||
'power': {
|
||||
'required': 'Power is required.'
|
||||
}
|
||||
};
|
||||
get power() { return this.heroForm.get('power'); }
|
||||
// #enddocregion form-group
|
||||
}
|
||||
// #enddocregion
|
||||
|
@ -1,13 +0,0 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { HeroFormReactiveComponent } from './hero-form-reactive.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [ SharedModule, ReactiveFormsModule ],
|
||||
declarations: [ HeroFormReactiveComponent ],
|
||||
exports: [ HeroFormReactiveComponent ]
|
||||
})
|
||||
export class HeroFormReactiveModule { }
|
@ -6,9 +6,8 @@ import { AbstractControl, NG_VALIDATORS, Validator, ValidatorFn, Validators } fr
|
||||
/** A hero's name can't match the given regular expression */
|
||||
export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
|
||||
return (control: AbstractControl): {[key: string]: any} => {
|
||||
const name = control.value;
|
||||
const no = nameRe.test(name);
|
||||
return no ? {'forbiddenName': {name}} : null;
|
||||
const forbidden = nameRe.test(control.value);
|
||||
return forbidden ? {'forbiddenName': {value: control.value}} : null;
|
||||
};
|
||||
}
|
||||
// #enddocregion custom-validator
|
||||
@ -20,23 +19,12 @@ export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
|
||||
providers: [{provide: NG_VALIDATORS, useExisting: ForbiddenValidatorDirective, multi: true}]
|
||||
// #enddocregion directive-providers
|
||||
})
|
||||
export class ForbiddenValidatorDirective implements Validator, OnChanges {
|
||||
export class ForbiddenValidatorDirective implements Validator {
|
||||
@Input() forbiddenName: string;
|
||||
private valFn = Validators.nullValidator;
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
const change = changes['forbiddenName'];
|
||||
if (change) {
|
||||
const val: string | RegExp = change.currentValue;
|
||||
const re = val instanceof RegExp ? val : new RegExp(val, 'i');
|
||||
this.valFn = forbiddenNameValidator(re);
|
||||
} else {
|
||||
this.valFn = Validators.nullValidator;
|
||||
}
|
||||
}
|
||||
|
||||
validate(control: AbstractControl): {[key: string]: any} {
|
||||
return this.valFn(control);
|
||||
return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
// #enddocregion directive
|
||||
|
@ -1,9 +0,0 @@
|
||||
// #docregion
|
||||
export class Hero {
|
||||
constructor(
|
||||
public id: number,
|
||||
public name: string,
|
||||
public power: string,
|
||||
public alterEgo?: string
|
||||
) { }
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { ForbiddenValidatorDirective } from './forbidden-name.directive';
|
||||
import { SubmittedComponent } from './submitted.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule],
|
||||
declarations: [ ForbiddenValidatorDirective, SubmittedComponent ],
|
||||
exports: [ ForbiddenValidatorDirective, SubmittedComponent,
|
||||
CommonModule ]
|
||||
})
|
||||
export class SharedModule { }
|
@ -1,32 +0,0 @@
|
||||
// #docregion
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
|
||||
import { Hero } from './hero';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-submitted',
|
||||
template: `
|
||||
<div *ngIf="submitted">
|
||||
<h2>You submitted the following:</h2>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">Name</div>
|
||||
<div class="col-xs-9 pull-left">{{ hero.name }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">Alter Ego</div>
|
||||
<div class="col-xs-9 pull-left">{{ hero.alterEgo }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">Power</div>
|
||||
<div class="col-xs-9 pull-left">{{ hero.power }}</div>
|
||||
</div>
|
||||
<br>
|
||||
<button class="btn btn-default" (click)="onClick()">Edit</button>
|
||||
</div>`
|
||||
})
|
||||
export class SubmittedComponent {
|
||||
@Input() hero: Hero;
|
||||
@Input() submitted = false;
|
||||
@Output() submittedChange = new EventEmitter<boolean>();
|
||||
onClick() { this.submittedChange.emit(false); }
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
<!-- #docregion -->
|
||||
<div class="container">
|
||||
|
||||
<h1>Template-Driven Form</h1>
|
||||
<!-- #docregion form-tag-->
|
||||
<form #heroForm="ngForm">
|
||||
<!-- #enddocregion form-tag-->
|
||||
<div [hidden]="heroForm.submitted">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
<!-- #docregion name-with-error-msg -->
|
||||
<!-- #docregion name-input -->
|
||||
<input id="name" name="name" class="form-control"
|
||||
required minlength="4" forbiddenName="bob"
|
||||
[(ngModel)]="hero.name" #name="ngModel" >
|
||||
<!-- #enddocregion name-input -->
|
||||
|
||||
<div *ngIf="name.invalid && (name.dirty || name.touched)"
|
||||
class="alert alert-danger">
|
||||
|
||||
<div *ngIf="name.errors.required">
|
||||
Name is required.
|
||||
</div>
|
||||
<div *ngIf="name.errors.minlength">
|
||||
Name must be at least 4 characters long.
|
||||
</div>
|
||||
<div *ngIf="name.errors.forbiddenName">
|
||||
Name cannot be Bob.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- #enddocregion name-with-error-msg -->
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input id="alterEgo" class="form-control"
|
||||
name="alterEgo" [(ngModel)]="hero.alterEgo" >
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
<select id="power" name="power" class="form-control"
|
||||
required [(ngModel)]="hero.power" #power="ngModel" >
|
||||
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
|
||||
<div *ngIf="power.errors && power.touched" class="alert alert-danger">
|
||||
<div *ngIf="power.errors.required">Power is required.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-default"
|
||||
[disabled]="heroForm.invalid">Submit</button>
|
||||
<button type="button" class="btn btn-default"
|
||||
(click)="heroForm.resetForm({})">Reset</button>
|
||||
</div>
|
||||
|
||||
<div class="submitted-message" *ngIf="heroForm.submitted">
|
||||
<p>You've submitted your hero, {{ heroForm.value.name }}!</p>
|
||||
<button (click)="heroForm.resetForm({})">Add new hero</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
@ -0,0 +1,16 @@
|
||||
/* tslint:disable: member-ordering */
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-form-template',
|
||||
templateUrl: './hero-form-template.component.html'
|
||||
})
|
||||
export class HeroFormTemplateComponent {
|
||||
|
||||
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
|
||||
|
||||
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
|
||||
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { HeroFormTemplate1Component } from './hero-form-template1.component';
|
||||
import { HeroFormTemplate2Component } from './hero-form-template2.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [ SharedModule, FormsModule ],
|
||||
declarations: [ HeroFormTemplate1Component, HeroFormTemplate2Component ],
|
||||
exports: [ HeroFormTemplate1Component, HeroFormTemplate2Component ]
|
||||
})
|
||||
export class HeroFormTemplateModule { }
|
@ -1,61 +0,0 @@
|
||||
<!-- #docregion -->
|
||||
<div class="container">
|
||||
<div [hidden]="submitted">
|
||||
<h1>Hero Form 1 (Template)</h1>
|
||||
<!-- #docregion form-tag-->
|
||||
<form #heroForm="ngForm" *ngIf="active" (ngSubmit)="onSubmit()">
|
||||
<!-- #enddocregion form-tag-->
|
||||
<div class="form-group">
|
||||
<!-- #docregion name-with-error-msg -->
|
||||
<label for="name">Name</label>
|
||||
|
||||
<input type="text" id="name" class="form-control"
|
||||
required minlength="4" maxlength="24"
|
||||
name="name" [(ngModel)]="hero.name"
|
||||
#name="ngModel" >
|
||||
|
||||
<div *ngIf="name.errors && (name.dirty || name.touched)"
|
||||
class="alert alert-danger">
|
||||
<div [hidden]="!name.errors.required">
|
||||
Name is required
|
||||
</div>
|
||||
<div [hidden]="!name.errors.minlength">
|
||||
Name must be at least 4 characters long.
|
||||
</div>
|
||||
<div [hidden]="!name.errors.maxlength">
|
||||
Name cannot be more than 24 characters long.
|
||||
</div>
|
||||
</div>
|
||||
<!-- #enddocregion name-with-error-msg -->
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input type="text" id="alterEgo" class="form-control"
|
||||
name="alterEgo"
|
||||
[(ngModel)]="hero.alterEgo" >
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
<select id="power" class="form-control"
|
||||
name="power"
|
||||
[(ngModel)]="hero.power" required
|
||||
#power="ngModel" >
|
||||
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
|
||||
<div *ngIf="power.errors && power.touched" class="alert alert-danger">
|
||||
<div [hidden]="!power.errors.required">Power is required</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-default"
|
||||
[disabled]="!heroForm.form.valid">Submit</button>
|
||||
<button type="button" class="btn btn-default"
|
||||
(click)="addHero()">New Hero</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<hero-submitted [hero]="hero" [(submitted)]="submitted"></hero-submitted>
|
||||
</div>
|
@ -1,47 +0,0 @@
|
||||
/* tslint:disable: member-ordering */
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
|
||||
import { Hero } from '../shared/hero';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-form-template1',
|
||||
templateUrl: './hero-form-template1.component.html'
|
||||
})
|
||||
// #docregion class
|
||||
export class HeroFormTemplate1Component {
|
||||
|
||||
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
|
||||
|
||||
hero = new Hero(18, 'Dr. WhatIsHisWayTooLongName', this.powers[0], 'Dr. What');
|
||||
|
||||
submitted = false;
|
||||
|
||||
onSubmit() {
|
||||
this.submitted = true;
|
||||
}
|
||||
// #enddocregion class
|
||||
// #enddocregion
|
||||
// Reset the form with a new hero AND restore 'pristine' class state
|
||||
// by toggling 'active' flag which causes the form
|
||||
// to be removed/re-added in a tick via NgIf
|
||||
// TODO: Workaround until NgForm has a reset method (#6822)
|
||||
active = true;
|
||||
// #docregion
|
||||
// #docregion class
|
||||
|
||||
addHero() {
|
||||
this.hero = new Hero(42, '', '');
|
||||
// #enddocregion class
|
||||
// #enddocregion
|
||||
|
||||
this.active = false;
|
||||
setTimeout(() => this.active = true, 0);
|
||||
// #docregion
|
||||
// #docregion class
|
||||
}
|
||||
}
|
||||
// #enddocregion class
|
||||
// #enddocregion
|
@ -1,52 +0,0 @@
|
||||
<!-- #docregion -->
|
||||
<div class="container">
|
||||
<div [hidden]="submitted">
|
||||
<h1>Hero Form 2 (Template & Messages)</h1>
|
||||
<!-- #docregion form-tag-->
|
||||
<form #heroForm="ngForm" *ngIf="active" (ngSubmit)="onSubmit()">
|
||||
<!-- #enddocregion form-tag-->
|
||||
<div class="form-group">
|
||||
<!-- #docregion name-with-error-msg -->
|
||||
<label for="name">Name</label>
|
||||
|
||||
<!-- #docregion name-input -->
|
||||
<input type="text" id="name" class="form-control"
|
||||
required minlength="4" maxlength="24" forbiddenName="bob"
|
||||
name="name" [(ngModel)]="hero.name" >
|
||||
<!-- #enddocregion name-input -->
|
||||
|
||||
<div *ngIf="formErrors.name" class="alert alert-danger">
|
||||
{{ formErrors.name }}
|
||||
</div>
|
||||
<!-- #enddocregion name-with-error-msg -->
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="alterEgo">Alter Ego</label>
|
||||
<input type="text" id="alterEgo" class="form-control"
|
||||
name="alterEgo"
|
||||
[(ngModel)]="hero.alterEgo" >
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="power">Hero Power</label>
|
||||
<select id="power" class="form-control"
|
||||
name="power"
|
||||
[(ngModel)]="hero.power" required >
|
||||
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
|
||||
</select>
|
||||
|
||||
<div *ngIf="formErrors.power" class="alert alert-danger">
|
||||
{{ formErrors.power }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-default"
|
||||
[disabled]="!heroForm.form.valid">Submit</button>
|
||||
<button type="button" class="btn btn-default"
|
||||
(click)="addHero()">New Hero</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<hero-submitted [hero]="hero" [(submitted)]="submitted"></hero-submitted>
|
||||
</div>
|
@ -1,99 +0,0 @@
|
||||
/* tslint:disable: member-ordering forin */
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { Component, AfterViewChecked, ViewChild } from '@angular/core';
|
||||
import { NgForm } from '@angular/forms';
|
||||
|
||||
import { Hero } from '../shared/hero';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-form-template2',
|
||||
templateUrl: './hero-form-template2.component.html'
|
||||
})
|
||||
export class HeroFormTemplate2Component implements AfterViewChecked {
|
||||
|
||||
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
|
||||
|
||||
hero = new Hero(18, 'Dr. WhatIsHisWayTooLongName', this.powers[0], 'Dr. What');
|
||||
|
||||
submitted = false;
|
||||
|
||||
onSubmit() {
|
||||
this.submitted = true;
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// Reset the form with a new hero AND restore 'pristine' class state
|
||||
// by toggling 'active' flag which causes the form
|
||||
// to be removed/re-added in a tick via NgIf
|
||||
// TODO: Workaround until NgForm has a reset method (#6822)
|
||||
active = true;
|
||||
// #docregion
|
||||
|
||||
addHero() {
|
||||
this.hero = new Hero(42, '', '');
|
||||
// #enddocregion
|
||||
|
||||
this.active = false;
|
||||
setTimeout(() => this.active = true, 0);
|
||||
// #docregion
|
||||
}
|
||||
|
||||
// #docregion view-child
|
||||
heroForm: NgForm;
|
||||
@ViewChild('heroForm') currentForm: NgForm;
|
||||
|
||||
ngAfterViewChecked() {
|
||||
this.formChanged();
|
||||
}
|
||||
|
||||
formChanged() {
|
||||
if (this.currentForm === this.heroForm) { return; }
|
||||
this.heroForm = this.currentForm;
|
||||
if (this.heroForm) {
|
||||
this.heroForm.valueChanges
|
||||
.subscribe(data => this.onValueChanged(data));
|
||||
}
|
||||
}
|
||||
// #enddocregion view-child
|
||||
|
||||
// #docregion handler
|
||||
onValueChanged(data?: any) {
|
||||
if (!this.heroForm) { return; }
|
||||
const form = this.heroForm.form;
|
||||
|
||||
for (const field in this.formErrors) {
|
||||
// clear previous error message (if any)
|
||||
this.formErrors[field] = '';
|
||||
const control = form.get(field);
|
||||
|
||||
if (control && control.dirty && !control.valid) {
|
||||
const messages = this.validationMessages[field];
|
||||
for (const key in control.errors) {
|
||||
this.formErrors[field] += messages[key] + ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
formErrors = {
|
||||
'name': '',
|
||||
'power': ''
|
||||
};
|
||||
// #enddocregion handler
|
||||
|
||||
// #docregion messages
|
||||
validationMessages = {
|
||||
'name': {
|
||||
'required': 'Name is required.',
|
||||
'minlength': 'Name must be at least 4 characters long.',
|
||||
'maxlength': 'Name cannot be more than 24 characters long.',
|
||||
'forbiddenName': 'Someone named "Bob" cannot be a hero.'
|
||||
},
|
||||
'power': {
|
||||
'required': 'Power is required.'
|
||||
}
|
||||
};
|
||||
// #enddocregion messages
|
||||
}
|
||||
// #enddocregion
|
@ -1,3 +1,4 @@
|
||||
|
||||
.ng-valid[required], .ng-valid.required {
|
||||
border-left: 5px solid #42A948; /* green */
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ export class AppComponent {
|
||||
wolves = 0;
|
||||
gender = 'f';
|
||||
fly = true;
|
||||
logo = 'https://angular.io/resources/images/logos/angular/angular.png';
|
||||
logo = 'https://angular.io/assets/images/logos/angular/angular.png';
|
||||
count = 3;
|
||||
heroes: string[] = ['Magneta', 'Celeritas', 'Dynama'];
|
||||
inc(i: number) {
|
||||
|
6
aio/content/examples/i18n/src/app/app.locale_data.ts
Normal file
6
aio/content/examples/i18n/src/app/app.locale_data.ts
Normal file
@ -0,0 +1,6 @@
|
||||
// #docregion import-locale
|
||||
import { registerLocaleData } from '@angular/common';
|
||||
import localeFr from '@angular/common/i18n_data/locale_fr';
|
||||
|
||||
registerLocaleData(localeFr);
|
||||
// #enddocregion import-locale
|
@ -0,0 +1,7 @@
|
||||
// #docregion import-locale-extra
|
||||
import { registerLocaleData } from '@angular/common';
|
||||
import localeEnGB from '@angular/common/i18n_data/locale_en-GB';
|
||||
import localeEnGBExtra from '@angular/common/i18n_data/extra/locale_en-GB';
|
||||
|
||||
registerLocaleData(localeEnGB, localeEnGBExtra);
|
||||
// #enddocregion import-locale-extra
|
@ -1,15 +1,15 @@
|
||||
// #docplaster
|
||||
// #docregion without-missing-translation
|
||||
import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID, MissingTranslationStrategy } from '@angular/core';
|
||||
import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID, MissingTranslationStrategy, StaticProvider } from '@angular/core';
|
||||
import { CompilerConfig } from '@angular/compiler';
|
||||
|
||||
export function getTranslationProviders(): Promise<Object[]> {
|
||||
export function getTranslationProviders(): Promise<StaticProvider[]> {
|
||||
|
||||
// Get the locale id from the global
|
||||
const locale = document['locale'] as string;
|
||||
|
||||
// return no providers if fail to get translation file for locale
|
||||
const noProviders: Object[] = [];
|
||||
const noProviders: StaticProvider[] = [];
|
||||
|
||||
// No locale or U.S. English: no translation providers
|
||||
if (!locale || locale === 'en-US') {
|
||||
|
@ -28,7 +28,7 @@ describe('Pipes', function () {
|
||||
|
||||
it('should be able to toggle birthday formats', function () {
|
||||
let birthDayEle = element(by.css('hero-birthday2 > p'));
|
||||
expect(birthDayEle.getText()).toEqual(`The hero's birthday is 4/15/1988`);
|
||||
expect(birthDayEle.getText()).toEqual(`The hero's birthday is 4/15/88`);
|
||||
let buttonEle = element(by.cssContainingText('hero-birthday2 > button', 'Toggle Format'));
|
||||
expect(buttonEle.isDisplayed()).toBe(true);
|
||||
buttonEle.click().then(function() {
|
||||
|
@ -1,116 +0,0 @@
|
||||
/* #docregion , quickstart, toh */
|
||||
/* Master Styles */
|
||||
h1 {
|
||||
color: #369;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 250%;
|
||||
}
|
||||
h2, h3 {
|
||||
color: #444;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-weight: lighter;
|
||||
}
|
||||
body {
|
||||
margin: 2em;
|
||||
}
|
||||
/* #enddocregion quickstart */
|
||||
body, input[text], button {
|
||||
color: #888;
|
||||
font-family: Cambria, Georgia;
|
||||
}
|
||||
/* #enddocregion toh */
|
||||
a {
|
||||
cursor: pointer;
|
||||
cursor: hand;
|
||||
}
|
||||
button {
|
||||
font-family: Arial;
|
||||
background-color: #eee;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
cursor: hand;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #cfd8dc;
|
||||
}
|
||||
button:disabled {
|
||||
background-color: #eee;
|
||||
color: #aaa;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
/* Navigation link styles */
|
||||
nav a {
|
||||
padding: 5px 10px;
|
||||
text-decoration: none;
|
||||
margin-right: 10px;
|
||||
margin-top: 10px;
|
||||
display: inline-block;
|
||||
background-color: #eee;
|
||||
border-radius: 4px;
|
||||
}
|
||||
nav a:visited, a:link {
|
||||
color: #607D8B;
|
||||
}
|
||||
nav a:hover {
|
||||
color: #039be5;
|
||||
background-color: #CFD8DC;
|
||||
}
|
||||
nav a.active {
|
||||
color: #039be5;
|
||||
}
|
||||
|
||||
/* items class */
|
||||
.items {
|
||||
margin: 0 0 2em 0;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
width: 24em;
|
||||
}
|
||||
.items li {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
left: 0;
|
||||
background-color: #EEE;
|
||||
margin: .5em;
|
||||
padding: .3em 0;
|
||||
height: 1.6em;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.items li:hover {
|
||||
color: #607D8B;
|
||||
background-color: #DDD;
|
||||
left: .1em;
|
||||
}
|
||||
.items li.selected {
|
||||
background-color: #CFD8DC;
|
||||
color: white;
|
||||
}
|
||||
.items li.selected:hover {
|
||||
background-color: #BBD8DC;
|
||||
}
|
||||
.items .text {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
}
|
||||
.items .badge {
|
||||
display: inline-block;
|
||||
font-size: small;
|
||||
color: white;
|
||||
padding: 0.8em 0.7em 0 0.7em;
|
||||
background-color: #607D8B;
|
||||
line-height: 1em;
|
||||
position: relative;
|
||||
left: -1px;
|
||||
top: -4px;
|
||||
height: 1.8em;
|
||||
margin-right: .8em;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
/* #docregion toh */
|
||||
/* everywhere else */
|
||||
* {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser, element, by } from 'protractor';
|
||||
|
||||
describe('TypeScript to Javascript tests', function () {
|
||||
|
||||
beforeAll(function () {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
it('should display the basic component example', function () {
|
||||
testTag('hero-view', 'Hero Detail: Windstorm');
|
||||
});
|
||||
|
||||
it('should display the component example with lifecycle methods', function () {
|
||||
testTag('hero-lifecycle', 'Hero: Windstorm');
|
||||
});
|
||||
|
||||
it('should display component with DI example', function () {
|
||||
testTag('hero-di', 'Hero: Windstorm');
|
||||
});
|
||||
|
||||
it('should display component with DI using @Inject example', function () {
|
||||
testTag('hero-di-inject', 'Hero: Windstorm');
|
||||
});
|
||||
|
||||
it('should support optional, attribute, and query injections', function () {
|
||||
let app = element(by.css('hero-di-inject-additional'));
|
||||
let h1 = app.element(by.css('h1'));
|
||||
let okMsg = app.element(by.css('p'));
|
||||
|
||||
expect(h1.getText()).toBe('Tour of Heroes');
|
||||
app.element(by.buttonText('OK')).click();
|
||||
expect(okMsg.getText()).toBe('OK!');
|
||||
});
|
||||
|
||||
it('should support component with inputs and outputs', function () {
|
||||
let app = element(by.css('hero-io'));
|
||||
let confirmComponent = app.element(by.css('app-confirm'));
|
||||
|
||||
confirmComponent.element(by.buttonText('OK')).click();
|
||||
expect(app.element(by.cssContainingText('span', 'OK clicked')).isPresent()).toBe(true);
|
||||
|
||||
confirmComponent.element(by.buttonText('Cancel')).click();
|
||||
expect(app.element(by.cssContainingText('span', 'Cancel clicked')).isPresent()).toBe(true);
|
||||
});
|
||||
|
||||
it('should support host bindings and host listeners', function() {
|
||||
let app = element(by.css('hero-host'));
|
||||
let h1 = app.element(by.css('h1'));
|
||||
|
||||
expect(app.getAttribute('class')).toBe('heading');
|
||||
expect(app.getAttribute('title')).toContain('Tooltip');
|
||||
|
||||
h1.click();
|
||||
expect(h1.getAttribute('class')).toBe('active');
|
||||
|
||||
h1.click();
|
||||
browser.actions().doubleClick(h1.getWebElement()).perform();
|
||||
expect(h1.getAttribute('class')).toBe('active');
|
||||
});
|
||||
|
||||
it('should support content and view queries', function() {
|
||||
let app = element(by.css('hero-queries'));
|
||||
let windstorm = app.element(by.css('view-child:first-child'));
|
||||
|
||||
app.element(by.css('button')).click();
|
||||
expect(windstorm.element(by.css('h2')).getAttribute('class')).toBe('active');
|
||||
expect(windstorm.element(by.css('content-child')).getText()).toBe('Active');
|
||||
});
|
||||
|
||||
function testTag(selector: string, expectedText: string) {
|
||||
let component = element(by.css(selector));
|
||||
expect(component.getText()).toBe(expectedText);
|
||||
}
|
||||
|
||||
});
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"build": "build:babel"
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"description": "TypeScript to JavaScript",
|
||||
"basePath": "src/",
|
||||
"files":[
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js"
|
||||
],
|
||||
"tags":["cookbook"]
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
"es2015",
|
||||
"angular2"
|
||||
]
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
templateUrl: './app.component.html',
|
||||
styles: [
|
||||
// See hero-di-inject-additional.component
|
||||
'hero-host, hero-host-meta { border: 1px dashed black; display: block; padding: 4px;}',
|
||||
'.heading {font-style: italic}'
|
||||
]
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'ES6 JavaScript with Decorators';
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
<a id="toc"></a>
|
||||
<h1>{{title}}</h1>
|
||||
<a href="#class-metadata">Classes and Class Metadata</a><br>
|
||||
<a href="#io-metadata">Input and Output Decorators</a><br>
|
||||
<a href="#dependency-injection">Dependency Injection</a><br>
|
||||
<a href="#host-metadata">Host Metadata</a><br>
|
||||
<a href="#view-child-metadata">View and Child Metadata</a><br>
|
||||
|
||||
<hr>
|
||||
<h4 id="class-metadata">Classes and Class Metadata</h4>
|
||||
<hero-view></hero-view>
|
||||
<hero-lifecycle></hero-lifecycle>
|
||||
|
||||
<hr>
|
||||
<h4 id="io-metadata">Input and Output Metadata</h4>
|
||||
<hero-io></hero-io>
|
||||
|
||||
<hr>
|
||||
<h4 id="dependency-injection">Dependency Injection</h4>
|
||||
<hero-di></hero-di>
|
||||
<hero-di-inject></hero-di-inject>
|
||||
<hero-di-inject-additional></hero-di-inject-additional>
|
||||
|
||||
<hr>
|
||||
<h4 id="host-metadata">Host Metadata</h4>
|
||||
<hero-host></hero-host>
|
||||
<hero-host-meta></hero-host-meta>
|
||||
|
||||
<hr>
|
||||
<h4 id="view-child-metadata">View and Child Metadata</h4>
|
||||
<hero-queries></hero-queries>
|
@ -1,55 +0,0 @@
|
||||
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { ConfirmComponent } from './confirm.component';
|
||||
// #docregion appimport
|
||||
import { HeroComponent } from './hero.component';
|
||||
// #enddocregion appimport
|
||||
import { HeroComponent as HeroDIComponent } from './hero-di.component';
|
||||
import { HeroComponent as HeroDIInjectComponent } from './hero-di-inject.component';
|
||||
import { HeroComponent as HeroDIInjectAdditionalComponent } from './hero-di-inject-additional.component';
|
||||
import { HeroHostComponent } from './hero-host.component';
|
||||
import { HeroHostMetaComponent } from './hero-host-meta.component';
|
||||
import { HeroIOComponent } from './hero-io.component';
|
||||
import { HeroComponent as HeroLifecycleComponent } from './hero-lifecycle.component';
|
||||
import { HeroQueriesComponent, ViewChildComponent, ContentChildComponent } from './hero-queries.component';
|
||||
import { HeroTitleComponent } from './hero-title.component';
|
||||
|
||||
import { DataService } from './data.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
ConfirmComponent,
|
||||
HeroComponent,
|
||||
HeroDIComponent,
|
||||
HeroDIInjectComponent,
|
||||
HeroDIInjectAdditionalComponent,
|
||||
HeroHostComponent, HeroHostMetaComponent,
|
||||
HeroIOComponent,
|
||||
HeroLifecycleComponent,
|
||||
HeroQueriesComponent, ViewChildComponent, ContentChildComponent,
|
||||
HeroTitleComponent
|
||||
],
|
||||
providers: [
|
||||
DataService,
|
||||
{ provide: 'heroName', useValue: 'Windstorm' }
|
||||
],
|
||||
bootstrap: [ AppComponent ],
|
||||
|
||||
// schemas: [ NO_ERRORS_SCHEMA ] // helpful for debugging
|
||||
})
|
||||
export class AppModule { }
|
||||
|
||||
/* tslint:disable no-unused-variable */
|
||||
// #docregion ng2import
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import {
|
||||
LocationStrategy,
|
||||
HashLocationStrategy
|
||||
} from '@angular/common';
|
||||
// #enddocregion ng2import
|
@ -1,21 +0,0 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
|
||||
// #docregion
|
||||
@Component({
|
||||
selector: 'app-confirm',
|
||||
templateUrl: './confirm.component.html'
|
||||
})
|
||||
export class ConfirmComponent {
|
||||
@Input() okMsg = '';
|
||||
@Input('cancelMsg') notOkMsg = '';
|
||||
@Output() ok = new EventEmitter();
|
||||
@Output('cancel') notOk = new EventEmitter();
|
||||
|
||||
onOkClick() {
|
||||
this.ok.emit(true);
|
||||
}
|
||||
onNotOkClick() {
|
||||
this.notOk.emit(true);
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
@ -1,6 +0,0 @@
|
||||
<button (click)="onOkClick()">
|
||||
{{okMsg}}
|
||||
</button>
|
||||
<button (click)="onNotOkClick()">
|
||||
{{notOkMsg}}
|
||||
</button>
|
@ -1,10 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class DataService {
|
||||
constructor() { }
|
||||
|
||||
getHeroName() {
|
||||
return 'Windstorm';
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-di-inject-additional',
|
||||
template: `<hero-title title="Tour of Heroes"></hero-title>`
|
||||
})
|
||||
export class HeroComponent { }
|
@ -1,13 +0,0 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
|
||||
// #docregion
|
||||
@Component({
|
||||
selector: 'hero-di-inject',
|
||||
template: `<h1>Hero: {{name}}</h1>`
|
||||
})
|
||||
export class HeroComponent {
|
||||
constructor(@Inject('heroName') name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
@ -1,15 +0,0 @@
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
import { DataService } from './data.service';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-di',
|
||||
template: `<h1>Hero: {{name}}</h1>`
|
||||
})
|
||||
export class HeroComponent {
|
||||
name = '';
|
||||
constructor(dataService: DataService) {
|
||||
this.name = dataService.getHeroName();
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
@ -1,44 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
// #docregion
|
||||
@Component({
|
||||
selector: 'hero-host-meta',
|
||||
template: `
|
||||
<h1 [class.active]="active">Hero Host in Metadata</h1>
|
||||
<div>Heading clicks: {{clicks}}</div>
|
||||
`,
|
||||
host: {
|
||||
// HostBindings to the <hero-host-meta> element
|
||||
'[title]': 'title',
|
||||
'[class.heading]': 'headingClass',
|
||||
|
||||
// HostListeners on the entire <hero-host-meta> element
|
||||
'(click)': 'clicked()',
|
||||
'(mouseenter)': 'enter($event)',
|
||||
'(mouseleave)': 'leave($event)'
|
||||
},
|
||||
// Styles within (but excluding) the <hero-host-meta> element
|
||||
styles: ['.active {background-color: coral;}']
|
||||
})
|
||||
export class HeroHostMetaComponent {
|
||||
title = 'Hero Host in Metadata Tooltip';
|
||||
headingClass = true;
|
||||
|
||||
active = false;
|
||||
clicks = 0;
|
||||
|
||||
clicked() {
|
||||
this.clicks += 1;
|
||||
}
|
||||
|
||||
enter(event: Event) {
|
||||
this.active = true;
|
||||
this.headingClass = false;
|
||||
}
|
||||
|
||||
leave(event: Event) {
|
||||
this.active = false;
|
||||
this.headingClass = true;
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
@ -1,39 +0,0 @@
|
||||
import { Component, HostBinding, HostListener } from '@angular/core';
|
||||
|
||||
// #docregion
|
||||
@Component({
|
||||
selector: 'hero-host',
|
||||
template: `
|
||||
<h1 [class.active]="active">Hero Host in Decorators</h1>
|
||||
<div>Heading clicks: {{clicks}}</div>
|
||||
`,
|
||||
// Styles within (but excluding) the <hero-host> element
|
||||
styles: ['.active {background-color: yellow;}']
|
||||
})
|
||||
export class HeroHostComponent {
|
||||
// HostBindings to the <hero-host> element
|
||||
@HostBinding() title = 'Hero Host in Decorators Tooltip';
|
||||
@HostBinding('class.heading') headingClass = true;
|
||||
|
||||
active = false;
|
||||
clicks = 0;
|
||||
|
||||
// HostListeners on the entire <hero-host> element
|
||||
@HostListener('click')
|
||||
clicked() {
|
||||
this.clicks += 1;
|
||||
}
|
||||
|
||||
@HostListener('mouseenter', ['$event'])
|
||||
enter(event: Event) {
|
||||
this.active = true;
|
||||
this.headingClass = false;
|
||||
}
|
||||
|
||||
@HostListener('mouseleave', ['$event'])
|
||||
leave(event: Event) {
|
||||
this.active = false;
|
||||
this.headingClass = true;
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
@ -1,26 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-io',
|
||||
template: `
|
||||
<app-confirm [okMsg]="'OK'"
|
||||
[cancelMsg]="'Cancel'"
|
||||
(ok)="onOk()"
|
||||
(cancel)="onCancel()">
|
||||
</app-confirm>
|
||||
<span *ngIf="okClicked">OK clicked</span>
|
||||
<span *ngIf="cancelClicked">Cancel clicked</span>
|
||||
`
|
||||
})
|
||||
export class HeroIOComponent {
|
||||
okClicked = false;
|
||||
cancelClicked = false;
|
||||
|
||||
onOk() {
|
||||
this.okClicked = true;
|
||||
}
|
||||
|
||||
onCancel() {
|
||||
this.cancelClicked = true;
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-lifecycle',
|
||||
template: `<h1>Hero: {{name}}</h1>`
|
||||
})
|
||||
export class HeroComponent {
|
||||
name = '';
|
||||
ngOnInit() {
|
||||
// todo: fetch from server async
|
||||
setTimeout(() => this.name = 'Windstorm', 0);
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
import {
|
||||
Component,
|
||||
ContentChild,
|
||||
Input,
|
||||
QueryList,
|
||||
ViewChildren
|
||||
} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'content-child',
|
||||
template: `
|
||||
<span class="content-child" *ngIf="active">
|
||||
Active
|
||||
</span>`
|
||||
})
|
||||
export class ContentChildComponent {
|
||||
active = false;
|
||||
|
||||
activate() {
|
||||
this.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
// #docregion content
|
||||
@Component({
|
||||
selector: 'view-child',
|
||||
template: `
|
||||
<h2 [class.active]=active>
|
||||
{{hero.name}}
|
||||
<ng-content></ng-content>
|
||||
</h2>`,
|
||||
styles: ['.active {font-weight: bold; background-color: skyblue;}']
|
||||
})
|
||||
export class ViewChildComponent {
|
||||
@Input() hero;
|
||||
active = false;
|
||||
|
||||
@ContentChild(ContentChildComponent) content;
|
||||
|
||||
activate() {
|
||||
this.active = !this.active;
|
||||
this.content.activate();
|
||||
}
|
||||
}
|
||||
// #enddocregion content
|
||||
|
||||
////////////////////
|
||||
|
||||
// #docregion view
|
||||
@Component({
|
||||
selector: 'hero-queries',
|
||||
template: `
|
||||
<view-child *ngFor="let hero of heroData" [hero]="hero">
|
||||
<content-child></content-child>
|
||||
</view-child>
|
||||
<button (click)="activate()">{{buttonLabel}} All</button>
|
||||
`
|
||||
})
|
||||
export class HeroQueriesComponent {
|
||||
active = false;
|
||||
heroData = [
|
||||
{id: 1, name: 'Windstorm'},
|
||||
{id: 2, name: 'LaughingGas'}
|
||||
];
|
||||
|
||||
@ViewChildren(ViewChildComponent) views;
|
||||
|
||||
activate() {
|
||||
this.active = !this.active;
|
||||
this.views.forEach(
|
||||
view => view.activate()
|
||||
);
|
||||
}
|
||||
|
||||
get buttonLabel() {
|
||||
return this.active ? 'Deactivate' : 'Activate';
|
||||
}
|
||||
}
|
||||
// #enddocregion view
|
@ -1,25 +0,0 @@
|
||||
import { Attribute, Component, Inject, Optional } from '@angular/core';
|
||||
|
||||
// #docregion
|
||||
// #docregion templateUrl
|
||||
@Component({
|
||||
selector: 'hero-title',
|
||||
templateUrl: './hero-title.component.html'
|
||||
})
|
||||
// #enddocregion templateUrl
|
||||
export class HeroTitleComponent {
|
||||
msg = '';
|
||||
constructor(
|
||||
@Inject('titlePrefix') @Optional() titlePrefix,
|
||||
@Attribute('title') title
|
||||
) {
|
||||
this.titlePrefix = titlePrefix;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
ok() {
|
||||
this.msg = 'OK!';
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
@ -1,4 +0,0 @@
|
||||
<!-- #docregion -->
|
||||
<h1>{{titlePrefix}} {{title}}</h1>
|
||||
<button (click)="ok()">OK</button>
|
||||
<p>{{ msg }}</p>
|
@ -1,15 +0,0 @@
|
||||
// #docregion
|
||||
// #docregion metadata
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'hero-view',
|
||||
template: '<h1>{{title}}: {{getName()}}</h1>'
|
||||
})
|
||||
// #docregion appexport, class
|
||||
export class HeroComponent {
|
||||
title = 'Hero Detail';
|
||||
getName() {return 'Windstorm'; }
|
||||
}
|
||||
// #enddocregion appexport, class
|
||||
// #enddocregion metadata
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<base href="/">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<title>TypeScript to JavaScript</title>
|
||||
|
||||
<!-- Polyfill(s) for older browsers -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
|
||||
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||
|
||||
<script src="systemjs.config.js"></script>
|
||||
<script>
|
||||
System.import('main.js').catch(function(err){ console.error(err); });
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<my-app>Loading...</my-app>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,4 +0,0 @@
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { AppModule } from './app/app.module';
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"build": "build:babel"
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"description": "TypeScript to JavaScript",
|
||||
"basePath": "src/",
|
||||
"files":[
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js"
|
||||
],
|
||||
"tags":["cookbook"]
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
"es2015"
|
||||
]
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
export class AppComponent {
|
||||
constructor() {
|
||||
this.title = 'Plain ES6 JavaScript';
|
||||
}
|
||||
}
|
||||
|
||||
AppComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'my-app',
|
||||
templateUrl: './app.component.html',
|
||||
styles: [
|
||||
// See hero-di-inject-additional.component
|
||||
'hero-host { border: 1px dashed black; display: block; padding: 4px;}',
|
||||
'.heading {font-style: italic}'
|
||||
]
|
||||
})
|
||||
];
|
@ -1,30 +0,0 @@
|
||||
<a id="toc"></a>
|
||||
<h1>{{title}}</h1>
|
||||
<a href="#class-metadata">Classes and Class Metadata</a><br>
|
||||
<a href="#io-metadata">Input and Output Metadata</a><br>
|
||||
<a href="#dependency-injection">Dependency Injection</a><br>
|
||||
<a href="#host-metadata">Host Metadata</a><br>
|
||||
<a href="#view-child-metadata">View and Child Metadata</a><br>
|
||||
|
||||
<hr>
|
||||
<h4 id="class-metadata">Classes and Class Metadata</h4>
|
||||
<hero-view></hero-view>
|
||||
<hero-lifecycle></hero-lifecycle>
|
||||
|
||||
<hr>
|
||||
<h4 id="io-metadata">Input and Output Metadata</h4>
|
||||
<hero-io></hero-io>
|
||||
|
||||
<hr>
|
||||
<h4 id="dependency-injection">Dependency Injection</h4>
|
||||
<hero-di></hero-di>
|
||||
<hero-di-inject></hero-di-inject>
|
||||
<hero-di-inject-additional></hero-di-inject-additional>
|
||||
|
||||
<hr>
|
||||
<h4 id="host-metadata">Host Metadata</h4>
|
||||
<hero-host></hero-host>
|
||||
|
||||
<hr>
|
||||
<h4 id="view-child-metadata">View and Child Metadata</h4>
|
||||
<hero-queries></hero-queries>
|
@ -1,56 +0,0 @@
|
||||
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { ConfirmComponent } from './confirm.component';
|
||||
// #docregion appimport
|
||||
import { HeroComponent } from './hero.component';
|
||||
|
||||
// #enddocregion appimport
|
||||
import { HeroComponent as HeroDIComponent } from './hero-di.component';
|
||||
import { HeroComponent as HeroDIInjectComponent } from './hero-di-inject.component';
|
||||
import { HeroComponent as HeroDIInjectAdditionalComponent } from './hero-di-inject-additional.component';
|
||||
import { HeroHostComponent } from './hero-host.component';
|
||||
import { HeroIOComponent } from './hero-io.component';
|
||||
import { HeroComponent as HeroLifecycleComponent } from './hero-lifecycle.component';
|
||||
import { HeroQueriesComponent, ViewChildComponent, ContentChildComponent } from './hero-queries.component';
|
||||
import { HeroTitleComponent } from './hero-title.component';
|
||||
|
||||
import { DataService } from './data.service';
|
||||
|
||||
export class AppModule { }
|
||||
|
||||
AppModule.annotations = [
|
||||
new NgModule({
|
||||
imports: [ BrowserModule],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
ConfirmComponent,
|
||||
HeroComponent,
|
||||
HeroDIComponent,
|
||||
HeroDIInjectComponent,
|
||||
HeroDIInjectAdditionalComponent,
|
||||
HeroHostComponent,
|
||||
HeroIOComponent,
|
||||
HeroLifecycleComponent,
|
||||
HeroQueriesComponent, ViewChildComponent, ContentChildComponent,
|
||||
HeroTitleComponent
|
||||
],
|
||||
providers: [
|
||||
DataService,
|
||||
{ provide: 'heroName', useValue: 'Windstorm' }
|
||||
],
|
||||
bootstrap: [ AppComponent ],
|
||||
|
||||
// schemas: [ NO_ERRORS_SCHEMA ] // helpful for debugging
|
||||
})
|
||||
]
|
||||
|
||||
/* tslint:disable no-unused-variable */
|
||||
// #docregion ng2import
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import {
|
||||
LocationStrategy,
|
||||
HashLocationStrategy
|
||||
} from '@angular/common';
|
||||
// #enddocregion ng2import
|
@ -1,31 +0,0 @@
|
||||
import { Component, EventEmitter } from '@angular/core';
|
||||
|
||||
// #docregion
|
||||
export class ConfirmComponent {
|
||||
constructor(){
|
||||
this.ok = new EventEmitter();
|
||||
this.notOk = new EventEmitter();
|
||||
}
|
||||
onOkClick() {
|
||||
this.ok.emit(true);
|
||||
}
|
||||
onNotOkClick() {
|
||||
this.notOk.emit(true);
|
||||
}
|
||||
}
|
||||
|
||||
ConfirmComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'app-confirm',
|
||||
templateUrl: './confirm.component.html',
|
||||
inputs: [
|
||||
'okMsg',
|
||||
'notOkMsg: cancelMsg'
|
||||
],
|
||||
outputs: [
|
||||
'ok',
|
||||
'notOk: cancel'
|
||||
]
|
||||
})
|
||||
];
|
||||
// #enddocregion
|
@ -1,6 +0,0 @@
|
||||
<button (click)="onOkClick()">
|
||||
{{okMsg}}
|
||||
</button>
|
||||
<button (click)="onNotOkClick()">
|
||||
{{notOkMsg}}
|
||||
</button>
|
@ -1,13 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
export class DataService {
|
||||
constructor() {
|
||||
}
|
||||
getHeroName() {
|
||||
return 'Windstorm';
|
||||
}
|
||||
}
|
||||
|
||||
DataService.annotations = [
|
||||
new Injectable()
|
||||
];
|
@ -1,10 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
export class HeroComponent { }
|
||||
|
||||
HeroComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'hero-di-inject-additional',
|
||||
template: `<hero-title title="Tour of Heroes"></hero-title>`
|
||||
})
|
||||
];
|
@ -1,20 +0,0 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
|
||||
// #docregion
|
||||
export class HeroComponent {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
HeroComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'hero-di-inject',
|
||||
template: `<h1>Hero: {{name}}</h1>`
|
||||
})
|
||||
];
|
||||
|
||||
HeroComponent.parameters = [
|
||||
[new Inject('heroName')]
|
||||
];
|
||||
// #enddocregion
|
@ -1,21 +0,0 @@
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
import { DataService } from './data.service';
|
||||
|
||||
export class HeroComponent {
|
||||
constructor(dataService) {
|
||||
this.name = dataService.getHeroName();
|
||||
}
|
||||
}
|
||||
|
||||
HeroComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'hero-di',
|
||||
template: `<h1>Hero: {{name}}</h1>`
|
||||
})
|
||||
];
|
||||
|
||||
HeroComponent.parameters = [
|
||||
[DataService]
|
||||
];
|
||||
// #enddocregion
|
@ -1,50 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
// #docregion
|
||||
export class HeroHostComponent {
|
||||
constructor() {
|
||||
this.active = false;
|
||||
this.clicks = 0;
|
||||
this.headingClass = true;
|
||||
this.title = 'Hero Host Tooltip';
|
||||
}
|
||||
|
||||
clicked() {
|
||||
this.clicks += 1;
|
||||
}
|
||||
|
||||
enter(event) {
|
||||
this.active = true;
|
||||
this.headingClass = false;
|
||||
}
|
||||
|
||||
leave(event) {
|
||||
this.active = false;
|
||||
this.headingClass = true;
|
||||
}
|
||||
}
|
||||
|
||||
// #docregion metadata
|
||||
HeroHostComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'hero-host',
|
||||
template: `
|
||||
<h1 [class.active]="active">Hero Host</h1>
|
||||
<div>Heading clicks: {{clicks}}</div>
|
||||
`,
|
||||
host: {
|
||||
// HostBindings to the <hero-host> element
|
||||
'[title]': 'title',
|
||||
'[class.heading]': 'headingClass',
|
||||
'(click)': 'clicked()',
|
||||
|
||||
// HostListeners on the entire <hero-host> element
|
||||
'(mouseenter)': 'enter($event)',
|
||||
'(mouseleave)': 'leave($event)'
|
||||
},
|
||||
// Styles within (but excluding) the <hero-host> element
|
||||
styles: ['.active {background-color: yellow;}']
|
||||
})
|
||||
];
|
||||
// #enddocregion metadata
|
||||
// #enddocregion
|
@ -1,31 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
export class HeroIOComponent {
|
||||
constructor() {
|
||||
this.okClicked = false;
|
||||
this.cancelClicked = false;
|
||||
}
|
||||
|
||||
onOk() {
|
||||
this.okClicked = true;
|
||||
}
|
||||
|
||||
onCancel() {
|
||||
this.cancelClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
HeroIOComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'hero-io',
|
||||
template: `
|
||||
<app-confirm [okMsg]="'OK'"
|
||||
[cancelMsg]="'Cancel'"
|
||||
(ok)="onOk()"
|
||||
(cancel)="onCancel()">
|
||||
</app-confirm>
|
||||
<span *ngIf="okClicked">OK clicked</span>
|
||||
<span *ngIf="cancelClicked">Cancel clicked</span>
|
||||
`
|
||||
})
|
||||
];
|
@ -1,15 +0,0 @@
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
export class HeroComponent {
|
||||
ngOnInit() {
|
||||
// todo: fetch from server async
|
||||
setTimeout(() => this.name = 'Windstorm', 0);
|
||||
}
|
||||
}
|
||||
|
||||
HeroComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'hero-lifecycle',
|
||||
template: `<h1>Hero: {{name}}</h1>`
|
||||
})
|
||||
];
|
@ -1,97 +0,0 @@
|
||||
import {
|
||||
Component,
|
||||
ContentChild,
|
||||
Input,
|
||||
QueryList,
|
||||
ViewChildren
|
||||
} from '@angular/core';
|
||||
|
||||
export class ContentChildComponent {
|
||||
constructor() {
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
activate() {
|
||||
this.active = !this.active;
|
||||
}
|
||||
}
|
||||
|
||||
ContentChildComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'content-child',
|
||||
template: `
|
||||
<span class="content-child" *ngIf="active">
|
||||
Active
|
||||
</span>`
|
||||
})
|
||||
];
|
||||
|
||||
////////////////////
|
||||
|
||||
// #docregion content
|
||||
export class ViewChildComponent {
|
||||
constructor() {
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
activate() {
|
||||
this.active = !this.active;
|
||||
this.content.activate();
|
||||
}
|
||||
}
|
||||
|
||||
ViewChildComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'view-child',
|
||||
template: `<h2 [class.active]=active>
|
||||
{{hero.name}}
|
||||
<ng-content></ng-content>
|
||||
</h2>`,
|
||||
styles: ['.active {font-weight: bold; background-color: skyblue;}'],
|
||||
inputs: ['hero'],
|
||||
queries: {
|
||||
content: new ContentChild(ContentChildComponent)
|
||||
}
|
||||
})
|
||||
];
|
||||
// #enddocregion content
|
||||
|
||||
////////////////////
|
||||
|
||||
// #docregion view
|
||||
export class HeroQueriesComponent {
|
||||
constructor(){
|
||||
this.active = false;
|
||||
this.heroData = [
|
||||
{id: 1, name: 'Windstorm'},
|
||||
{id: 2, name: 'LaughingGas'}
|
||||
];
|
||||
}
|
||||
|
||||
activate() {
|
||||
this.active = !this.active;
|
||||
this.views.forEach(
|
||||
view => view.activate()
|
||||
);
|
||||
}
|
||||
|
||||
get buttonLabel() {
|
||||
return this.active ? 'Deactivate' : 'Activate';
|
||||
}
|
||||
}
|
||||
|
||||
HeroQueriesComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'hero-queries',
|
||||
template: `
|
||||
<view-child *ngFor="let hero of heroData" [hero]="hero">
|
||||
<content-child></content-child>
|
||||
</view-child>
|
||||
<button (click)="activate()">{{buttonLabel}} All</button>
|
||||
`,
|
||||
queries: {
|
||||
views: new ViewChildren(ViewChildComponent)
|
||||
}
|
||||
})
|
||||
];
|
||||
// #enddocregion view
|
@ -1,28 +0,0 @@
|
||||
import { Attribute, Component, Inject, Optional } from '@angular/core';
|
||||
|
||||
// #docregion
|
||||
export class HeroTitleComponent {
|
||||
constructor(titlePrefix, title) {
|
||||
this.titlePrefix = titlePrefix;
|
||||
this.title = title;
|
||||
this.msg = '';
|
||||
}
|
||||
|
||||
ok() {
|
||||
this.msg = 'OK!';
|
||||
}
|
||||
}
|
||||
|
||||
// #docregion templateUrl
|
||||
HeroTitleComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'hero-title',
|
||||
templateUrl: './hero-title.component.html'
|
||||
})
|
||||
];
|
||||
// #enddocregion templateUrl
|
||||
|
||||
HeroTitleComponent.parameters = [
|
||||
[new Optional(), new Inject('titlePrefix')],
|
||||
[new Attribute('title')]
|
||||
];
|
@ -1,4 +0,0 @@
|
||||
<!-- #docregion -->
|
||||
<h1>{{titlePrefix}} {{title}}</h1>
|
||||
<button (click)="ok()">OK</button>
|
||||
<p>{{ msg }}</p>
|
@ -1,21 +0,0 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
// #docregion metadata
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
// #docregion appexport, class
|
||||
export class HeroComponent {
|
||||
constructor() {
|
||||
this.title = 'Hero Detail';
|
||||
}
|
||||
getName() {return 'Windstorm'; }
|
||||
}
|
||||
// #enddocregion appexport, class
|
||||
|
||||
HeroComponent.annotations = [
|
||||
new Component({
|
||||
selector: 'hero-view',
|
||||
template: '<h1>{{title}}: {{getName()}}</h1>'
|
||||
})
|
||||
];
|
||||
// #enddocregion metadata
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<base href="/">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<title>TypeScript to JavaScript</title>
|
||||
|
||||
<!-- Polyfill(s) for older browsers -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
|
||||
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||
|
||||
<script src="systemjs.config.js"></script>
|
||||
<script>
|
||||
System.import('main.js').catch(function(err){ console.error(err); });
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<my-app>Loading...</my-app>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,4 +0,0 @@
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { AppModule } from './app/app.module';
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"build": "build:babel"
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"description": "TypeScript to JavaScript",
|
||||
"basePath": "src/",
|
||||
"files":[
|
||||
"!**/karma*.*"
|
||||
],
|
||||
"tags":["cookbook"]
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
<a id="toc"></a>
|
||||
<h1>{{title}}</h1>
|
||||
<a href="#class-metadata">Classes and Class Metadata</a><br>
|
||||
<a href="#interfaces">Interfaces</a><br>
|
||||
<a href="#io-metadata">Input and Output Metadata</a><br>
|
||||
<a href="#dependency-injection">Dependency Injection</a><br>
|
||||
<a href="#host-metadata">Host Metadata</a><br>
|
||||
<a href="#view-child-metadata">View and Child Metadata</a><br>
|
||||
|
||||
<hr>
|
||||
<h4 id="class-metadata">Classes and Class Metadata</h4>
|
||||
<hero-view></hero-view>
|
||||
<h4 id="class-metadata-dsl">Classes and Class Metadata (DSL)</h4>
|
||||
<hero-view-dsl></hero-view-dsl>
|
||||
|
||||
<hr>
|
||||
<h4 id="interfaces">Interfaces</h4>
|
||||
<hero-lifecycle></hero-lifecycle>
|
||||
<h4 id="interfaces-dsl">Interfaces (DSL)</h4>
|
||||
<hero-lifecycle-dsl></hero-lifecycle-dsl>
|
||||
|
||||
<hr>
|
||||
<h4 id="io-metadata">Input and Output Metadata</h4>
|
||||
<hero-io></hero-io>
|
||||
<h4 id="io-metadata-dsl">Input and Output Metadata (DSL)</h4>
|
||||
<hero-io-dsl></hero-io-dsl>
|
||||
|
||||
<hr>
|
||||
<h4 id="dependency-injection">Dependency Injection</h4>
|
||||
<hero-di></hero-di>
|
||||
<hero-di-inject></hero-di-inject>
|
||||
<hero-di-inject-additional></hero-di-inject-additional>
|
||||
|
||||
<h4 id="dependency-injection-dsl">Dependency Injection (DSL)</h4>
|
||||
<hero-di-dsl></hero-di-dsl>
|
||||
<hero-di-inject-dsl></hero-di-inject-dsl>
|
||||
<hero-di-inject-additional-dsl></hero-di-inject-additional-dsl>
|
||||
|
||||
<hr>
|
||||
<h4 id="host-metadata">Host Metadata</h4>
|
||||
<hero-host></hero-host>
|
||||
<h4 id="host-metadata-dsl">Host Metadata (DSL)</h4>
|
||||
<hero-host-dsl></hero-host-dsl>
|
||||
|
||||
<hr>
|
||||
<h4 id="view-child-metadata">View and Child Metadata (DSL)</h4>
|
||||
<hero-queries></hero-queries>
|
@ -1,20 +0,0 @@
|
||||
(function(app) {
|
||||
|
||||
app.AppComponent = AppComponent;
|
||||
function AppComponent() {
|
||||
this.title = 'ES5 JavaScript';
|
||||
}
|
||||
|
||||
AppComponent.annotations = [
|
||||
new ng.core.Component({
|
||||
selector: 'my-app',
|
||||
templateUrl: 'app/app.component.html',
|
||||
styles: [
|
||||
// See hero-di-inject-additional.component
|
||||
'hero-host, hero-host-dsl { border: 1px dashed black; display: block; padding: 4px;}',
|
||||
'.heading {font-style: italic}'
|
||||
]
|
||||
})
|
||||
];
|
||||
|
||||
})(window.app = window.app || {});
|
@ -1,46 +0,0 @@
|
||||
(function(app) {
|
||||
|
||||
app.AppModule = AppModule;
|
||||
function AppModule() { }
|
||||
|
||||
AppModule.annotations = [
|
||||
new ng.core.NgModule({
|
||||
imports: [ ng.platformBrowser.BrowserModule ],
|
||||
declarations: [
|
||||
app.AppComponent,
|
||||
app.ConfirmComponent, app.ConfirmDslComponent,
|
||||
app.HeroComponent, app.HeroDslComponent,
|
||||
app.HeroDIComponent, app.HeroDIDslComponent,
|
||||
app.HeroDIInjectComponent, app.HeroDIInjectDslComponent,
|
||||
app.HeroDIInjectAdditionalComponent, app.HeroDIInjectAdditionalDslComponent,
|
||||
app.HeroHostComponent, app.HeroHostDslComponent,
|
||||
app.HeroIOComponent, app.HeroIODslComponent,
|
||||
app.HeroLifecycleComponent, app.HeroLifecycleDslComponent,
|
||||
app.heroQueries.HeroQueriesComponent, app.heroQueries.ViewChildComponent, app.heroQueries.ContentChildComponent,
|
||||
app.HeroTitleComponent, app.HeroTitleDslComponent
|
||||
],
|
||||
providers: [
|
||||
app.DataService,
|
||||
{ provide: 'heroName', useValue: 'Windstorm' }
|
||||
],
|
||||
bootstrap: [ app.AppComponent ],
|
||||
|
||||
// schemas: [ ng.core.NO_ERRORS_SCHEMA ] // helpful for debugging!
|
||||
})
|
||||
]
|
||||
|
||||
})(window.app = window.app || {});
|
||||
|
||||
|
||||
///// For documentation only /////
|
||||
(function () {
|
||||
// #docregion appimport
|
||||
var HeroComponent = app.HeroComponent;
|
||||
// #enddocregion appimport
|
||||
|
||||
// #docregion ng2import
|
||||
var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic;
|
||||
var LocationStrategy = ng.common.LocationStrategy;
|
||||
var HashLocationStrategy = ng.common.HashLocationStrategy;
|
||||
// #enddocregion ng2import
|
||||
})
|
@ -1,6 +0,0 @@
|
||||
<button (click)="onOkClick()">
|
||||
{{okMsg}}
|
||||
</button>
|
||||
<button (click)="onNotOkClick()">
|
||||
{{notOkMsg}}
|
||||
</button>
|
@ -1,75 +0,0 @@
|
||||
(function(app) {
|
||||
|
||||
// #docregion
|
||||
app.ConfirmComponent = ConfirmComponent;
|
||||
|
||||
ConfirmComponent.annotations = [
|
||||
new ng.core.Component({
|
||||
selector: 'app-confirm',
|
||||
templateUrl: 'app/confirm.component.html',
|
||||
inputs: [
|
||||
'okMsg',
|
||||
'notOkMsg: cancelMsg'
|
||||
],
|
||||
outputs: [
|
||||
'ok',
|
||||
'notOk: cancel'
|
||||
]
|
||||
})
|
||||
];
|
||||
|
||||
function ConfirmComponent() {
|
||||
this.ok = new ng.core.EventEmitter();
|
||||
this.notOk = new ng.core.EventEmitter();
|
||||
}
|
||||
|
||||
ConfirmComponent.prototype.onOkClick = function() {
|
||||
this.ok.emit(true);
|
||||
}
|
||||
|
||||
ConfirmComponent.prototype.onNotOkClick = function() {
|
||||
this.notOk.emit(true);
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
})(window.app = window.app || {});
|
||||
|
||||
/////// DSL version ////////
|
||||
|
||||
(function(app) {
|
||||
|
||||
var old = app.ConfirmComponent;
|
||||
|
||||
// #docregion dsl
|
||||
app.ConfirmComponent = ng.core.Component({
|
||||
selector: 'app-confirm-dsl',
|
||||
templateUrl: 'app/confirm.component.html',
|
||||
inputs: [
|
||||
'okMsg',
|
||||
'notOkMsg: cancelMsg'
|
||||
],
|
||||
outputs: [
|
||||
'ok',
|
||||
'notOk: cancel'
|
||||
]
|
||||
})
|
||||
.Class({
|
||||
constructor: function ConfirmComponent() {
|
||||
this.ok = new ng.core.EventEmitter();
|
||||
this.notOk = new ng.core.EventEmitter();
|
||||
},
|
||||
|
||||
onOkClick: function() {
|
||||
this.ok.emit(true);
|
||||
},
|
||||
|
||||
onNotOkClick: function() {
|
||||
this.notOk.emit(true);
|
||||
}
|
||||
});
|
||||
// #enddocregion dsl
|
||||
|
||||
app.ConfirmDslComponent = app.ConfirmComponent;
|
||||
app.ConfirmComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
@ -1,10 +0,0 @@
|
||||
(function(app) {
|
||||
|
||||
app.DataService = DataService;
|
||||
function DataService() { }
|
||||
|
||||
DataService.prototype.getHeroName = function() {
|
||||
return 'Windstorm';
|
||||
};
|
||||
|
||||
})(window.app = window.app || {});
|
@ -1,36 +0,0 @@
|
||||
(function(app) {
|
||||
|
||||
var old = app.HeroComponent;
|
||||
|
||||
app.HeroComponent = HeroComponent;
|
||||
|
||||
HeroComponent.annotations = [
|
||||
new ng.core.Component({
|
||||
selector: 'hero-di-inject-additional',
|
||||
template: '<hero-title title="Tour of Heroes"></hero-title>'
|
||||
})
|
||||
];
|
||||
|
||||
function HeroComponent() {}
|
||||
|
||||
app.HeroDIInjectAdditionalComponent = app.HeroComponent;
|
||||
app.HeroComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
||||
|
||||
////// DSL Version /////////
|
||||
(function(app) {
|
||||
|
||||
var old = app.HeroComponent;
|
||||
|
||||
app.HeroComponent = ng.core.Component({
|
||||
selector: 'hero-di-inject-additional-dsl',
|
||||
template: '<hero-title-dsl title="Tour of Heroes"></hero-title-dsl>'
|
||||
}).Class({
|
||||
constructor: function HeroComponent() { }
|
||||
});
|
||||
|
||||
app.HeroDIInjectAdditionalDslComponent = app.HeroComponent;
|
||||
app.HeroComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
@ -1,51 +0,0 @@
|
||||
(function(app) {
|
||||
|
||||
var old = app.HeroComponent;
|
||||
|
||||
// #docregion
|
||||
app.HeroComponent = HeroComponent;
|
||||
|
||||
HeroComponent.annotations = [
|
||||
new ng.core.Component({
|
||||
selector: 'hero-di-inject',
|
||||
template: '<h1>Hero: {{name}}</h1>'
|
||||
})
|
||||
];
|
||||
|
||||
HeroComponent.parameters = [ 'heroName' ];
|
||||
|
||||
function HeroComponent(name) {
|
||||
this.name = name;
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
app.HeroDIInjectComponent = app.HeroComponent;
|
||||
app.HeroComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
||||
|
||||
/////// DSL version ////////
|
||||
|
||||
(function(app) {
|
||||
|
||||
var old = app.HeroComponent;
|
||||
|
||||
// #docregion dsl
|
||||
app.HeroComponent = ng.core.Component({
|
||||
selector: 'hero-di-inject-dsl',
|
||||
template: '<h1>Hero: {{name}}</h1>'
|
||||
})
|
||||
.Class({
|
||||
constructor: [
|
||||
new ng.core.Inject('heroName'),
|
||||
function HeroComponent(name) {
|
||||
this.name = name;
|
||||
}
|
||||
]
|
||||
});
|
||||
// #enddocregion dsl
|
||||
|
||||
app.HeroDIInjectDslComponent = app.HeroComponent;
|
||||
app.HeroComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
@ -1,51 +0,0 @@
|
||||
(function(app) {
|
||||
|
||||
var old = app.HeroComponent;
|
||||
|
||||
// #docregion
|
||||
app.HeroComponent = HeroComponent;
|
||||
|
||||
HeroComponent.annotations = [
|
||||
new ng.core.Component({
|
||||
selector: 'hero-di',
|
||||
template: '<h1>Hero: {{name}}</h1>'
|
||||
})
|
||||
];
|
||||
|
||||
HeroComponent.parameters = [ app.DataService ];
|
||||
|
||||
function HeroComponent(dataService) {
|
||||
this.name = dataService.getHeroName();
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
app.HeroDIComponent = app.HeroComponent;
|
||||
app.HeroComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
||||
|
||||
////// DSL Version /////
|
||||
|
||||
(function(app) {
|
||||
|
||||
var old = app.HeroComponent;
|
||||
|
||||
// #docregion dsl
|
||||
app.HeroComponent = ng.core.Component({
|
||||
selector: 'hero-di-dsl',
|
||||
template: '<h1>Hero: {{name}}</h1>'
|
||||
})
|
||||
.Class({
|
||||
constructor: [
|
||||
app.DataService,
|
||||
function HeroComponent(service) {
|
||||
this.name = service.getHeroName();
|
||||
}
|
||||
]
|
||||
});
|
||||
// #enddocregion dsl
|
||||
|
||||
app.HeroDIDslComponent = app.HeroComponent;
|
||||
app.HeroComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
@ -1,107 +0,0 @@
|
||||
(function(app) {
|
||||
|
||||
var old = app.HeroComponent
|
||||
|
||||
// #docregion
|
||||
app.HeroComponent = HeroComponent;
|
||||
|
||||
HeroComponent.annotations = [
|
||||
new ng.core.Component({
|
||||
selector: 'hero-host',
|
||||
template:
|
||||
'<h1 [class.active]="active">Hero Host</h1>' +
|
||||
'<div>Heading clicks: {{clicks}}</div>',
|
||||
host: {
|
||||
// HostBindings to the <hero-host> element
|
||||
'[title]': 'title',
|
||||
'[class.heading]': 'headingClass',
|
||||
'(click)': 'clicked()',
|
||||
|
||||
// HostListeners on the entire <hero-host> element
|
||||
'(mouseenter)': 'enter($event)',
|
||||
'(mouseleave)': 'leave($event)'
|
||||
},
|
||||
// Styles within (but excluding) the <hero-host> element
|
||||
styles: ['.active {background-color: yellow;}']
|
||||
})
|
||||
];
|
||||
|
||||
function HeroComponent() {
|
||||
this.clicks = 0;
|
||||
this.headingClass = true;
|
||||
this.title = 'Hero Host Tooltip content';
|
||||
}
|
||||
|
||||
HeroComponent.prototype.clicked = function() {
|
||||
this.clicks += 1;
|
||||
}
|
||||
|
||||
HeroComponent.prototype.enter = function(event) {
|
||||
this.active = true;
|
||||
this.headingClass = false;
|
||||
}
|
||||
|
||||
HeroComponent.prototype.leave = function(event) {
|
||||
this.active = false;
|
||||
this.headingClass = true;
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
app.HeroHostComponent = app.HeroComponent;
|
||||
app.HeroComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
||||
|
||||
//// DSL Version ////
|
||||
|
||||
(function(app) {
|
||||
|
||||
var old = app.HeroComponent;
|
||||
|
||||
// #docregion dsl
|
||||
app.HeroComponent = ng.core.Component({
|
||||
selector: 'hero-host-dsl',
|
||||
template: `
|
||||
<h1 [class.active]="active">Hero Host (DSL)</h1>
|
||||
<div>Heading clicks: {{clicks}}</div>
|
||||
`,
|
||||
host: {
|
||||
// HostBindings to the <hero-host-dsl> element
|
||||
'[title]': 'title',
|
||||
'[class.heading]': 'headingClass',
|
||||
'(click)': 'clicked()',
|
||||
|
||||
// HostListeners on the entire <hero-host-dsl> element
|
||||
'(mouseenter)': 'enter($event)',
|
||||
'(mouseleave)': 'leave($event)'
|
||||
},
|
||||
// Styles within (but excluding) the <hero-host-dsl> element
|
||||
styles: ['.active {background-color: coral;}']
|
||||
})
|
||||
.Class({
|
||||
constructor: function HeroComponent() {
|
||||
this.clicks = 0;
|
||||
this.headingClass = true;
|
||||
this.title = 'Hero Host Tooltip DSL content';
|
||||
},
|
||||
|
||||
clicked() {
|
||||
this.clicks += 1;
|
||||
},
|
||||
|
||||
enter(event) {
|
||||
this.active = true;
|
||||
this.headingClass = false;
|
||||
},
|
||||
|
||||
leave(event) {
|
||||
this.active = false;
|
||||
this.headingClass = true;
|
||||
}
|
||||
});
|
||||
// #enddocregion dsl
|
||||
|
||||
app.HeroHostDslComponent = app.HeroComponent;
|
||||
app.HeroComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
@ -1,7 +0,0 @@
|
||||
<app-confirm-dsl [okMsg]="'OK'"
|
||||
[cancelMsg]="'Cancel'"
|
||||
(ok)="onOk()"
|
||||
(cancel)="onCancel()">
|
||||
</app-confirm-dsl>
|
||||
<span *ngIf="okClicked">OK clicked</span>
|
||||
<span *ngIf="cancelClicked">Cancel clicked</span>
|
@ -1,7 +0,0 @@
|
||||
<app-confirm [okMsg]="'OK'"
|
||||
[cancelMsg]="'Cancel'"
|
||||
(ok)="onOk()"
|
||||
(cancel)="onCancel()">
|
||||
</app-confirm>
|
||||
<span *ngIf="okClicked">OK clicked</span>
|
||||
<span *ngIf="cancelClicked">Cancel clicked</span>
|
@ -1,52 +0,0 @@
|
||||
(function(app) {
|
||||
|
||||
var old = app.HeroComponent
|
||||
|
||||
app.HeroComponent = HeroComponent;
|
||||
|
||||
HeroComponent.annotations = [
|
||||
new ng.core.Component({
|
||||
selector: 'hero-io',
|
||||
templateUrl: 'app/hero-io.component.html'
|
||||
})
|
||||
];
|
||||
|
||||
function HeroComponent() { }
|
||||
|
||||
HeroComponent.prototype.onOk = function() {
|
||||
this.okClicked = true;
|
||||
}
|
||||
|
||||
HeroComponent.prototype.onCancel = function() {
|
||||
this.cancelClicked = true;
|
||||
}
|
||||
|
||||
app.HeroIOComponent = app.HeroComponent;
|
||||
app.HeroComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
||||
|
||||
///// DSL Version ////
|
||||
|
||||
(function(app) {
|
||||
|
||||
var old = app.HeroComponent
|
||||
|
||||
app.HeroComponent = ng.core.Component({
|
||||
selector: 'hero-io-dsl',
|
||||
templateUrl: 'app/hero-io-dsl.component.html'
|
||||
})
|
||||
.Class({
|
||||
constructor: function HeroComponent() { },
|
||||
onOk: function() {
|
||||
this.okClicked = true;
|
||||
},
|
||||
onCancel: function() {
|
||||
this.cancelClicked = true;
|
||||
}
|
||||
});
|
||||
|
||||
app.HeroIODslComponent = app.HeroComponent;
|
||||
app.HeroComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
@ -1,52 +0,0 @@
|
||||
// #docplaster
|
||||
(function(app) {
|
||||
|
||||
var old = app.HeroComponent;
|
||||
|
||||
// #docregion
|
||||
app.HeroComponent = HeroComponent;
|
||||
|
||||
HeroComponent.annotations = [
|
||||
new ng.core.Component({
|
||||
selector: 'hero-lifecycle',
|
||||
template: '<h1>Hero: {{name}}</h1>'
|
||||
})
|
||||
];
|
||||
|
||||
function HeroComponent() { }
|
||||
|
||||
HeroComponent.prototype.ngOnInit = function() {
|
||||
// todo: fetch from server async
|
||||
setTimeout(() => this.name = 'Windstorm', 0);
|
||||
};
|
||||
// #enddocregion
|
||||
|
||||
app.HeroLifecycleComponent = app.HeroComponent;
|
||||
app.HeroComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
||||
|
||||
/////// DSL version ////
|
||||
|
||||
(function(app) {
|
||||
|
||||
var old = app.HeroComponent;
|
||||
|
||||
// #docregion dsl
|
||||
app.HeroComponent = ng.core.Component({
|
||||
selector: 'hero-lifecycle-dsl',
|
||||
template: '<h1>Hero: {{name}}</h1>'
|
||||
})
|
||||
.Class({
|
||||
constructor: function HeroComponent() { },
|
||||
ngOnInit: function() {
|
||||
// todo: fetch from server async
|
||||
setTimeout(() => this.name = 'Windstorm', 0);
|
||||
}
|
||||
});
|
||||
// #enddocregion dsl
|
||||
|
||||
app.HeroLifecycleDslComponent = app.HeroComponent;
|
||||
app.HeroComponent = old;
|
||||
|
||||
})(window.app = window.app || {});
|
@ -1,92 +0,0 @@
|
||||
(function(app) {
|
||||
|
||||
app.heroQueries = app.heroQueries || {};
|
||||
|
||||
app.heroQueries.ContentChildComponent = ng.core.Component({
|
||||
selector: 'content-child',
|
||||
template:
|
||||
'<span class="content-child" *ngIf="active">' +
|
||||
'Active' +
|
||||
'</span>'
|
||||
}).Class({
|
||||
constructor: function ContentChildComponent() {
|
||||
this.active = false;
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this.active = !this.active;
|
||||
}
|
||||
});
|
||||
|
||||
////////////////////
|
||||
|
||||
// #docregion content
|
||||
app.heroQueries.ViewChildComponent = ng.core.Component({
|
||||
selector: 'view-child',
|
||||
template:
|
||||
'<h2 [class.active]=active>' +
|
||||
'{{hero.name}} ' +
|
||||
'<ng-content></ng-content>' +
|
||||
'</h2>',
|
||||
styles: ['.active {font-weight: bold; background-color: skyblue;}'],
|
||||
inputs: ['hero'],
|
||||
queries: {
|
||||
content: new ng.core.ContentChild(app.heroQueries.ContentChildComponent)
|
||||
}
|
||||
})
|
||||
.Class({
|
||||
constructor: function HeroQueriesHeroComponent() {
|
||||
this.active = false;
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this.active = !this.active;
|
||||
this.content.activate();
|
||||
}
|
||||
});
|
||||
// #enddocregion content
|
||||
|
||||
////////////////////
|
||||
|
||||
// #docregion view
|
||||
app.heroQueries.HeroQueriesComponent = ng.core.Component({
|
||||
selector: 'hero-queries',
|
||||
template:
|
||||
'<view-child *ngFor="let hero of heroData" [hero]="hero">' +
|
||||
'<content-child></content-child>' +
|
||||
'</view-child>' +
|
||||
'<button (click)="activate()">{{buttonLabel}} All</button>',
|
||||
queries: {
|
||||
views: new ng.core.ViewChildren(app.heroQueries.ViewChildComponent)
|
||||
}
|
||||
})
|
||||
.Class({
|
||||
constructor: function HeroQueriesComponent() {
|
||||
this.active = false;
|
||||
this.heroData = [
|
||||
{id: 1, name: 'Windstorm'},
|
||||
{id: 2, name: 'LaughingGas'}
|
||||
];
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this.active = !this.active;
|
||||
this.views.forEach(function(view) {
|
||||
view.activate();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// #docregion defined-property
|
||||
// add prototype property w/ getter outside the DSL
|
||||
var proto = app.heroQueries.HeroQueriesComponent.prototype;
|
||||
Object.defineProperty(proto, "buttonLabel", {
|
||||
get: function () {
|
||||
return this.active ? 'Deactivate' : 'Activate';
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
// #enddocregion defined-property
|
||||
// #enddocregion view
|
||||
|
||||
})(window.app = window.app || {});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user