Compare commits

...

130 Commits

Author SHA1 Message Date
1e1af7ffcb docs: changelog for 5.0.0-beta.2 release 2017-08-02 13:23:27 -07:00
a84b2bc945 release: cut the 5.0.0-beta.2 release 2017-08-02 13:21:07 -07:00
7abcb99d57 docs: add changelog for 4.3.3 2017-08-02 13:19:00 -07:00
49cd8513e4 feat(router): add events tracking activation of individual routes
* Adds `ChildActivationStart` and `ChildActivationEnd`
* Adds test to verify the PreActivation phase of routing
2017-08-01 10:44:00 -07:00
82b067fc40 build: ignore node_modules for tslint 2017-08-01 10:13:44 -07:00
9479a106bb build: enable TSLint on the packages folder 2017-07-31 15:47:57 -07:00
e64b54b67b fix(compiler): do not consider arguments when determining recursion
The static reflectory check for macro function recursion was too
agressive and disallowed calling a function with argument that also
calls the same function. For example, it disallowed nested animation
groups.

Fixes: #17467
2017-07-31 13:42:31 -07:00
cc2a4c41f9 build(aio): fix warning about missing <h1>
Fixes #17549
2017-07-31 13:40:07 -07:00
a11542a375 docs(aio): fixed list format in FormArray section 2017-07-31 11:31:05 -07:00
b6c4af6495 feat(compiler-cli): automatically lower lambda expressions in metadata 2017-07-31 11:30:44 -07:00
67dff7bd5d feat(tsc-wrapped): allow values to be substituted by collector clients
Also reenabled tests that were unintentionally disabled when they were
moved from tools/@angular.
2017-07-31 11:30:44 -07:00
381471d338 fix(compiler): fix for element needing implicit parent placed in top-level ng-container
fixes #18314
2017-07-31 11:30:19 -07:00
ebef5e697a feat(forms): add options arg to abstract controls
FormControls, FormGroups, and FormArrays now optionally accept an options
object as their second argument. Validators and async validators can be
passed in as part of this options object (though they can still be passed
in as the second and third arg as before).

```ts
const c = new FormControl(, {
   validators: [Validators.required],
   asyncValidators: [myAsyncValidator]
});
```

This commit also adds support for passing arrays of validators and async
validators to FormGroups and FormArrays, which formerly only accepted
individual functions.

```ts
const g = new FormGroup({
   one: new FormControl()
}, [myPasswordValidator, myOtherValidator]);
```

This change paves the way for adding more options to AbstractControls,
such as more fine-grained control of validation timing.
2017-07-31 11:29:32 -07:00
d71ae278ef fix(aio): fix links to source for paths with symlinks
Fixes #18353
2017-07-28 15:28:59 -07:00
46207538ef ci: short-circuit npm install for aio builds that use yarn only 2017-07-28 15:28:28 -07:00
71eb7437b6 docs(aio): delay ngUpgrade e2e test to avoid flakes 2017-07-28 15:28:28 -07:00
b5ffbe342b build: short-circuit build for AIO tasks 2017-07-28 15:28:28 -07:00
0f79223008 docs(aio): fix deprecated protractor API usage
`browser.getLocationAbsUrl()` is deprecated.
We should use `browser.getCurrentUrl()` instead.
2017-07-28 15:28:28 -07:00
a085223331 ci(aio): test the example e2e files using local build of Angular 2017-07-28 15:28:28 -07:00
c383048259 build(aio): ignore generated aot files
Assets such as images and data which are generated
by the aot build were not being ignored.
2017-07-28 15:28:28 -07:00
b18eb04b46 docs(aio): remove generated styles.css file
This file should have been ignored as it is created
during the build of the example
2017-07-28 15:28:28 -07:00
c8c2ab012a build(aio): support overriding the Angular packages in examples with locally built ones 2017-07-28 15:28:28 -07:00
ecff8e6c93 build(aio): refactor and test the example-boilerplate tool 2017-07-28 15:28:28 -07:00
51f1da1b85 ci: shard the aio example e2e tests 2017-07-28 15:28:28 -07:00
a5e18c4cdf ci(aio): support sharding of example e2e tests 2017-07-28 15:28:28 -07:00
cf6284656f build(aio): upgrade @angular/material to 2.0.0-meta.8 2017-07-28 15:26:45 -07:00
3182ddaf3e build(aio): upgrade @angular/* to 4.3.1 2017-07-28 15:26:45 -07:00
416ed691e5 docs(aio): fix URLSearchParams interface link to MDN
Fixes #18367
2017-07-28 15:26:04 -07:00
0fb7484d51 refactor(aio): move content-specific images to content/images/
Fixes #17053
2017-07-28 15:06:49 -07:00
6a3454e81e refactor(aio): rename unused directories to _unused 2017-07-28 15:06:49 -07:00
c3fbe87012 fix(aio): fix link to logo in example 2017-07-28 15:06:49 -07:00
24117d7a49 refactor(aio): move unused images to unused directories
This prevents the ServiceWorker from prefetching unnecessary files.
2017-07-28 15:06:49 -07:00
5808153359 docs: add changelog for 5.0.0.-beta.1 2017-07-27 14:59:24 -07:00
9030c8a03e release: cut the 5.0.0-beta.1 release 2017-07-27 14:57:38 -07:00
b14fc06fa2 docs: add changelog for 4.3.2 2017-07-27 14:52:35 -07:00
a7f2468184 Revert "fix(router): should throw when lazy loaded module doesn't define any routes (#15001)"
This reverts commit 82923a381d.
2017-07-27 10:53:01 -07:00
fae47d86b3 refactor(forms): move value accessor tests into own spec (#18356)
PR Close #18356
2017-07-26 17:55:37 -05:00
d20ac14fe2 refactor(compiler-cli): allow custom error checking function in ngc (#18355)
PR Close #18355
2017-07-26 17:55:31 -05:00
cae3e6dca0 ci: give ownership of ngc-wrapped to compiler-cli maintainers (#18354)
PR Close #18354
2017-07-26 17:55:24 -05:00
086f4aa72c fix(router): child CanActivate guard should wait for parent to complete (#18110)
Closes #15670

PR Close #18110
2017-07-26 17:11:22 -05:00
82923a381d fix(router): should throw when lazy loaded module doesn't define any routes (#15001)
Closes #14596

PR Close #15001
2017-07-26 17:11:07 -05:00
5152abb037 docs(aio): add my details as a contributor (#18315)
PR Close #18315
2017-07-26 17:11:07 -05:00
67f7032321 fix(aio): correctly process markdown link in "Browser Support" (#18349)
The markdown processor expects an empty line between an opening tag and the
markdown content. (If there is no empty line, the content is interpreted as
plain HTML.)
Previously, the line between the opening `<td>` and the content contained
whitespace, which caused the content to be interpreted as HTML and not markdown.

Fixes #18312

PR Close #18349
2017-07-26 16:07:26 -05:00
205abe8140 build: fix broken bazel build (#18335) 2017-07-26 09:40:33 -07:00
b582e2b311 docs(aio): update examples to 4.3 2017-07-25 15:32:38 -07:00
91ab39cc55 docs(aio) - Fixed link to the glossary dash-case term (#18311)
PR Close #18311
2017-07-25 15:59:28 -05:00
38ec05f533 fix(compiler): add equiv & disp attributes to Xliff2 ICU placeholders (#18283)
Fixes #17344

PR Close #18283
2017-07-25 15:58:53 -05:00
b3085e96c2 feat(compiler): add representation of placeholders to xliff & xmb
Closes #17345
2017-07-25 15:58:53 -05:00
4cea2bd612 docs(platform-server): inline PlatformOptions and add doc strings (#18264)
Fix documentation for the options passed into renderModule and
renderModuleFactory.

PR Close #18264
2017-07-25 15:58:13 -05:00
ce47546188 refactor(compiler-cli): add support for browser compiler bundle (#17979)
PR Close #17979
2017-07-25 15:51:46 -05:00
6279e50d78 perf(core): use native addEventListener for faster rendering. (#18107)
Angular can make many assumptions about its event handlers. As a result
the bookkeeping for native addEventListener is significantly cheaper
than Zone's addEventLister which can't make such assumptions.

This change bypasses the Zone's addEventListener if present and always
uses the native addEventHandler. As a result registering event listeners
is about 3 times faster.

PR Close #18107
2017-07-25 15:35:44 -05:00
8bcb268140 ci: use chrome stable (#18307) 2017-07-25 11:18:24 -07:00
6fc5940959 build: Bazel builds ngfactories for packages/core (#18289)
PR Close #18289
2017-07-21 18:09:47 -05:00
0317c4c478 build: update bazel rules to latest (#18289) 2017-07-21 18:09:44 -05:00
b7a6f52d59 perf: latest tsickle to tree shake: abstract class methods & interfaces (#18236)
In previous version of tsickle abstract class methods were materialized.
The change resulted in 6Kb savings in angular.io bundle.

This change also required the removal of `@private` and `@return` type
annotation as it is explicitly dissalowed by tsickle.

NOTE: removed casts in front of `makeDecorator` due to:
https://github.com/angular/devkit/issues/45

```
 14938 Jul 19 13:16 0.b19e913fbdd6507d346b.chunk.js
  1535 Jul 19 13:16 inline.d8e019ea3cfdd86c2bd0.bundle.js
589178 Jul 19 13:16 main.54c97bcb6f254776b678.bundle.js
 34333 Jul 19 13:16 polyfills.4a3c9ca9481d53803157.bundle.js

 14938 Jul 18 16:55 0.b19e913fbdd6507d346b.chunk.js
  1535 Jul 18 16:55 inline.0c83abb44fad9a2768a7.bundle.js
582786 Jul 18 16:55 main.ea290db71b051813e156.bundle.js
 34333 Jul 18 16:55 polyfills.4a3c9ca9481d53803157.bundle.js

main savings: 589178 - 582786 = 6,392
```

PR Close #18236
2017-07-21 16:35:37 -05:00
7ae7573bc8 fix(core): invoke error handler outside of the Angular Zone (#18269)
In Node.JS console.log/error/warn functions actually resuls in a socket
write which in turn is considered by Zone.js as an async task.

This means that if there is any exception during change detection in a platform-server
application the error handler will make the Angular Zone unstable which
in turn will cause change detection to run on next tick and cause an
infinite loop.

It is also better to run the error handler outside of the Angular Zone
in general on all platforms so that an error in the error handler itself doesn't cause an
infinite loop.

Fixes #17073, #7774.

PR Close #18269
2017-07-21 16:35:23 -05:00
abee785821 refactor(tsc-wrapped): update tsc-wrapped to pass strictNullCheck (#18160)
PR Close #18160
2017-07-21 12:26:20 -05:00
619e625ee2 refactor(tsc-wrapped): move tsc-wrapped to the packages directory (#18160) 2017-07-21 12:26:16 -05:00
a6c635e69e ci: force precise on Travis (#18282)
PR Close #18282
2017-07-21 12:20:27 -05:00
e0a9625e46 test: fix bad merge (#18267)
PR Close #18267
2017-07-21 11:53:34 -05:00
fd0cc01eed fix(animations): export BrowserModule as apart of BrowserAnimationsModule (#18263)
PR Close #18263
2017-07-20 17:47:49 -05:00
1bfc77bf8c docs(aio): pngcrush all pngs (#18243)
PR Close #18243
2017-07-20 17:47:06 -05:00
a094769bca fix(platform-server): don't clobber parse5 properties when setting (#18237)
element properties.

Fixes #17050.

We now store all element properties in a separate 'properties' bag.

PR Close #18237
2017-07-20 17:46:37 -05:00
b4c98305da refactor(common): CleanUp HttpClient's imports (#18120)
PR Close #18120
2017-07-20 17:43:23 -05:00
a3a54299af fix(compiler): allow numbers for ICU message cases in lexer (#18095)
Closes #18095
Fixes #17799
2017-07-20 17:41:54 -05:00
15a3e2d307 ci(aio): fix aio payload script 2017-07-20 15:32:32 -07:00
54e0244954 Revert "docs: Remove unneeded file (#18106)"
This reverts commit 72fe45db2b.
2017-07-20 16:46:47 -05:00
43c33d5663 fix(upgrade): ensure downgraded components are created in the Angular zone (#18209)
PR Close #18209
2017-07-20 16:25:11 -05:00
6d7799fce9 test(upgrade): fail tests when there are AngularJS errors (#18209) 2017-07-20 16:25:07 -05:00
d31dc7b2b3 fix(upgrade): throw error if trying to get injector before setting (#18209)
Previously, `undefined` would be returned.
This change makes it easier to identify incorrect uses/bugs.
(Discussed in https://github.com/angular/angular/pull/18213#issuecomment-316191308.)
2017-07-20 16:24:45 -05:00
4cd4f7a208 aio: debounce search and delay index building (#18134)
* feat(aio): debounce search requests

* feat(aio): delay loading search worker and index
2017-07-20 09:51:40 -07:00
72fe45db2b docs: Remove unneeded file (#18106) 2017-07-20 09:50:17 -07:00
8d2819121b fix(aio): invalid formatting in architecure.md (#18159)
Introduced in e110a80caf (diff-9ac9c6a9277eea9856d75249a7c0a40aL127)
2017-07-20 09:48:02 -07:00
073e8ba2f2 docs(aio): replace old blog link (#18252)
Fixes #18233
* Docs(aio): Replaced old blog link Now with the Link to the new Angular.io Blog
* Removed double braces
2017-07-20 09:45:14 -07:00
5d1864fe68 docs: fixing invisible tag in README (#18245) 2017-07-20 09:43:42 -07:00
eaa843b55f ci: test bazel builds on travis (#18240) 2017-07-20 09:40:40 -07:00
c6cf678a07 docs(aio): Fixed typo with closing div 2017-07-20 09:38:28 -07:00
31cb418370 docs(aio): Fix http guide 2017-07-20 09:35:27 -07:00
8de44cf5e3 docs: fix wrong link in CONTRIBUTING.md (#18228)
The link to the CONTRIBUTING.md file was not correct
2017-07-20 09:33:15 -07:00
c67bad4f43 docs(router): minor typo (#18226)
Fix a minor typo in the description of a router spec.
2017-07-20 09:32:34 -07:00
410f21c75c docs(aio): fix typo in NgModule FAQs (#18211)
Fix #18133. Fix typo 'added' to 'add' in the 'Why does lazy loading create a child injector' section.
2017-07-20 09:07:30 -07:00
54ea5b6ffd docs: add changelog for 5.0.0-beta.0 2017-07-19 13:16:43 -07:00
0af03beaed release: cut the 5.0.0-beta.0 release 2017-07-19 13:12:50 -07:00
d71fa734f5 docs: add changelog for 4.3.1 2017-07-19 12:55:08 -07:00
6f45519d6f feat(animations): support :increment and :decrement transition aliases 2017-07-19 11:24:00 -07:00
65c9e13105 fix(compiler-cli): don't generate empty <target/> when extracting xliff
Fixes #15754
2017-07-19 09:45:52 -07:00
9208f0beea docs(aio): fix typo in Router documentation
Fix title and link to RouteConfigLoadEnd documentation
2017-07-19 15:01:50 +01:00
5344be5182 fix(animations): make sure @.disabled works in non-animation components
Note 4.3 only!

Prior to this fix when [@.disabled] was used in a component that
contained zero animation code it wouldn't register properly because the
renderer associated with that component was not an animation renderer.
This patch ensures that it gets registered even when there are no
animations set.
2017-07-18 16:37:04 -07:00
5db6f38b73 fix(animations): do not crash animations if a nested component fires CD during CD
Closes #18193
2017-07-18 15:22:43 -07:00
d22f8f54db fix(animations): always camelcase style property names that contain auto styles
Closes #17938
2017-07-18 15:22:30 -07:00
23146c9201 fix(animations): capture cancelled animation styles within grouped animations
Closes #17170
2017-07-18 15:22:10 -07:00
a5205c686e fix(upgrade): allow accessing AngularJS injector from downgraded module 2017-07-18 14:00:19 -07:00
807648251f fix(platform-server): provide XhrFactory for HttpClient 2017-07-18 13:59:26 -07:00
5c62e300e1 fix(common): send flushed body as error instead of null
fix #18181
2017-07-18 10:57:51 -07:00
256bc8acdd docs(http): Make name of injected HttpTestingController consistent 2017-07-18 10:35:56 -07:00
59c23c7bd7 feat(upgrade): propagate touched state of NgModelController 2017-07-18 10:35:35 -07:00
e03adb9edd docs(platform-server): add doc string for PlatformOptions 2017-07-18 10:34:57 -07:00
b399cb26d9 fix(router): terminal route in custom matcher 2017-07-18 10:25:18 -07:00
3b588fe2b0 docs: fix typo 2017-07-18 10:11:55 -07:00
95635c18c7 fix(compiler): ensure jit external id arguments names are unique
Fixes: #17558, #17378, #8676
2017-07-18 10:11:32 -07:00
e20cfe1bbc fix(router): canDeactivate guards should run from bottom to top
Closes #15657.
2017-07-18 10:04:39 -07:00
eb6fb5f87e fix(router): should navigate to the same url when config changes
Closes #15535
2017-07-18 10:04:11 -07:00
ad3029e786 fix(router): should run resolvers for the same route concurrently
Fixes #14279
2017-07-18 10:03:33 -07:00
2a2fe11e8d docs(aio): fix HttpClient setting new header sample 2017-07-18 10:02:27 -07:00
7d0f2cd51e fix(aio): remove title attribute from CodeExampleComponent
This was causing browser to add an unwanted tooltip that appeared
when the user hovers over the code.

See #17524
2017-07-18 17:55:28 +01:00
36faba1aab fix(aio): add quote to module 2017-07-18 17:48:04 +01:00
92179bcc64 fix(aio): do not wrap <code-tabs> tab labels
Fixes #17751
2017-07-18 17:43:59 +01:00
cdb069ab0e docs(aio): fix cheatsheet layout for narrow screens
* Tell the app that this will have no Table of Contents, since we have no
h2 headings anyway.
* Remove all the `nbsp;` from the code since that doesn't help with layout
* Remove side padding from sidenav-content when screen is narrow
* Restyle the cheatsheet table when the screen is narrow
2017-07-18 17:32:43 +01:00
c453b7bcfa build(aio): fail doc-gen if referenced images are missing 2017-07-18 11:45:05 +01:00
9d97163c64 docs(aio): fix broken image sources 2017-07-18 11:45:05 +01:00
f054c8360b docs(aio): fix up broken links 2017-07-18 11:45:05 +01:00
758848961e build(aio): abort doc-gen on dangling links 2017-07-18 11:45:05 +01:00
99b666614d build(aio): abort doc-gen if an example is missing
Closes #16936
2017-07-18 11:45:05 +01:00
3f331b53b2 docs(aio): update jelbourn photo 2017-07-17 14:51:11 -07:00
375d598a9f docs(aio): add George's fixes 2017-07-17 14:49:19 -07:00
cd67fced1c docs(aio): add npm install to Sublime instructions 2017-07-17 14:49:19 -07:00
a77cf7ee37 docs(aio): add Chuck's comments 2017-07-17 14:49:19 -07:00
2150b45954 docs(aio): add language service doc 2017-07-17 14:49:19 -07:00
9f99f4fae2 docs: fix HttpClient sample 2017-07-17 14:03:32 -07:00
c6ad212a98 docs(aio): fix HttpClient's interceptor sample 2017-07-17 14:03:16 -07:00
47b3ecd9a3 docs(http): fix "Expecting and answering requests" example mistake
Possibly overlooked testing documentation mistake fixed:
- `http.get('/data')` probably ought to be paired with `httpMock.expectOne('/data')` instead of `httpMock.expectOne('/data')`.
2017-07-17 14:01:44 -07:00
8c81c62d46 docs: fix HttpClient logging's sample 2017-07-17 14:01:24 -07:00
7e72317059 docs(http): fixed syntax error in AuthInterceptor example 2017-07-17 14:00:59 -07:00
0bb8423df9 ci: add GK and PBD to aio content and marketing groups 2017-07-17 10:52:34 -07:00
95698d93ad fix(aio): remove title from callout 2017-07-15 15:35:15 +01:00
c649da9f0a fix(aio): remove unused news.html file
Although outdated and not used, the file would be picked up and showed in search
results.
2017-07-15 15:29:20 +01:00
0bf0c35bca build(aio): render type parameters of API function exports
Fixes #18123
2017-07-15 08:52:35 +01:00
97e6901ded Revert "revert: revert: ci(aio): exclude changes in aio/content folder"
This reverts commit 3d85f72652.

Still causing repeated flakes on master.
2017-07-14 14:54:31 -07:00
30e76fcd80 feat(upgrade): support lazy-loading Angular module into AngularJS app 2017-07-14 14:10:30 -07:00
44b50427d9 refactor(upgrade): clean up some types 2017-07-14 14:10:30 -07:00
415 changed files with 8150 additions and 3936 deletions

View File

@ -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 @build_bazel_rules_typescript_node//:bin/npm install
- run: bazel build packages/...
- save_cache:
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}
paths:

View File

@ -69,8 +69,8 @@ groups:
- "*.lock"
- "tools/*"
exclude:
- "tools/@angular/tsc-wrapped/*"
- "tools/public_api_guard/*"
- "tools/ngc-wrapped/*"
- "aio/*"
users:
- IgorMinar #primary
@ -136,8 +136,9 @@ groups:
compiler-cli:
conditions:
files:
- "tools/@angular/tsc-wrapped/*"
- "packages/tsc-wrapped/*"
- "packages/compiler-cli/*"
- "tools/ngc-wrapped/*"
users:
- alexeagle
- chuckjaz
@ -256,6 +257,8 @@ groups:
files:
include:
- "aio/*"
exclude:
- "aio/content/*"
users:
- petebacondarwin #primary
- IgorMinar
@ -276,6 +279,8 @@ groups:
- Foxandxss
- stephenfluin
- wardbell
- petebacondarwin
- gkalpak
- IgorMinar #fallback
- mhevery #fallback
@ -289,5 +294,7 @@ groups:
users:
- juleskremer #primary
- stephenfluin
- petebacondarwin
- gkalpak
- IgorMinar #fallback
- mhevery #fallback

View File

@ -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:
@ -52,14 +55,15 @@ env:
- CI_MODE=browserstack_optional
- CI_MODE=docs_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

View File

@ -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",
]),
)

View File

@ -1,3 +1,126 @@
<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)

View File

@ -1,11 +1,17 @@
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "io_bazel_rules_typescript",
name = "build_bazel_rules_typescript",
remote = "https://github.com/bazelbuild/rules_typescript.git",
commit = "3a8404d",
tag = "0.0.5",
)
load("@io_bazel_rules_typescript//:defs.bzl", "node_repositories")
load("@build_bazel_rules_typescript//:defs.bzl", "node_repositories")
node_repositories(package_json = "//:package.json")
git_repository(
name = "build_bazel_rules_angular",
remote = "https://github.com/bazelbuild/rules_angular.git",
tag = "0.0.1",
)

View File

@ -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

View File

@ -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) {

View File

@ -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;
}

View File

@ -9,7 +9,8 @@ describe('PhoneCat Application', function() {
it('should redirect `index.html` to `index.html#!/phones', function() {
browser.get('index.html');
expect(browser.getLocationAbsUrl()).toBe('/phones');
browser.sleep(1000); // Not sure why this is needed but it is. The route change works fine.
expect(browser.getCurrentUrl()).toMatch(/\/phones$/);
});
describe('View: Phone list', function() {
@ -65,7 +66,7 @@ describe('PhoneCat Application', function() {
element.all(by.css('.phones li a')).first().click();
browser.sleep(1000); // Not sure why this is needed but it is. The route change works fine.
expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s');
expect(browser.getCurrentUrl()).toMatch(/\/phones\/nexus-s$/);
});
});

View File

@ -124,7 +124,7 @@ For example, import Angular's `Component` decorator from the `@angular/core` lib
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
You also import NgModules_ from Angular _libraries_ using JavaScript import statements:
You also import NgModules from Angular _libraries_ using JavaScript import statements:
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module" linenums="false"></code-example>

View File

@ -1,8 +1,8 @@
# Bootstrapping
An NgModule class describes how the application parts fit together.
Every application has at least one NgModule, the _root_ module
that you [bootstrap](guide/appmodule#main) to launch the application.
Every application has at least one NgModule, the _root_ module
that you [bootstrap](#main) to launch the application.
You can call it anything you want. The conventional name is `AppModule`.
The [setup](guide/setup) instructions produce a new project with the following minimal `AppModule`.
@ -25,7 +25,7 @@ The `@NgModule` decorator identifies `AppModule` as an `NgModule` class.
* **_bootstrap_** &mdash; the _root_ component that Angular creates and inserts into the `index.html` host web page.
The [NgModules](guide/ngmodule) guide dives deeply into the details of NgModules.
All you need to know at the moment is a few basics about these three properties.
All you need to know at the moment is a few basics about these three properties.
{@a imports}
@ -34,7 +34,7 @@ All you need to know at the moment is a few basics about these three properties.
### The _imports_ array
NgModules are a way to consolidate features that belong together into discrete units.
Many features of Angular itself are organized as NgModules.
Many features of Angular itself are organized as NgModules.
HTTP services are in the `HttpModule`. The router is in the `RouterModule`.
Eventually you may create a feature module.
@ -70,7 +70,7 @@ You add `import` statements to almost every application file.
They have nothing to do with Angular and Angular knows nothing about them.
The _module's_ `imports` array appears _exclusively_ in the `@NgModule` metadata object.
It tells Angular about specific _other_ NgModules&mdash;all of them classes decorated
It tells Angular about specific _other_ NgModules&mdash;all of them classes decorated
with `@NgModule`&mdash;that the application needs to function properly.
</div>
@ -110,7 +110,7 @@ Do not put any other kind of class in `declarations`; _not_ `NgModule` classes,
### The _bootstrap_ array
You launch the application by [_bootstrapping_](guide/bootstrapping#main) the root `AppModule`.
You launch the application by [_bootstrapping_](#main) the root `AppModule`.
Among other things, the _bootstrapping_ process creates the component(s) listed in the `bootstrap` array
and inserts each one into the browser DOM.
@ -127,13 +127,6 @@ Which brings us to the _bootstrapping_ process itself.
{@a main}
<l-main-section>
</l-main-section>
## Bootstrap in _main.ts_
There are many ways to bootstrap an application.

View File

@ -193,8 +193,8 @@ Angular supports most recent browsers. This includes the following specific vers
Angular's continuous integration process runs unit tests of the framework on all of these browsers for every pull request,
using <a href="https://saucelabs.com/">SauceLabs</a> and
Angular's continuous integration process runs unit tests of the framework on all of these browsers for every pull request,
using <a href="https://saucelabs.com/">SauceLabs</a> and
<a href="https://www.browserstack.com">Browserstack</a>.
@ -215,7 +215,7 @@ that implement missing features in JavaScript.
A particular browser may require at least one polyfill to run _any_ Angular application.
A particular browser may require at least one polyfill to run _any_ Angular application.
You may need additional polyfills for specific features.
The tables below can help you determine which polyfills to load, depending on the browsers you target and the features you use.
@ -241,7 +241,7 @@ These are the polyfills required to run an Angular application on each supported
<table>
<tr style="vertical-align: top">
<th>
Browsers (Desktop & Mobile)
</th>
@ -253,7 +253,7 @@ These are the polyfills required to run an Angular application on each supported
</tr>
<tr style="vertical-align: top">
<td>
Chrome, Firefox, Edge, Safari 9+
</td>
@ -265,7 +265,7 @@ These are the polyfills required to run an Angular application on each supported
</tr>
<tr style="vertical-align: top">
<td>
Safari 7 & 8, IE10 & 11, Android 4.1+
</td>
@ -279,7 +279,7 @@ These are the polyfills required to run an Angular application on each supported
</tr>
<tr style="vertical-align: top">
<td>
IE9
</td>
@ -309,7 +309,7 @@ Here are the features which may require additional polyfills:
<table>
<tr style="vertical-align: top">
<th>
Feature
</th>
@ -325,7 +325,7 @@ Here are the features which may require additional polyfills:
</tr>
<tr style="vertical-align: top">
<td>
[Animations](guide/animations)
@ -363,14 +363,14 @@ Here are the features which may require additional polyfills:
</tr>
<tr style="vertical-align: top">
<td>
[NgClass](api/common/NgClass) on SVG elements
</td>
<td>
[classList](guide/browser-support#classlist)
</td>
@ -382,16 +382,17 @@ Here are the features which may require additional polyfills:
</tr>
<tr style="vertical-align: top">
<td>
[Http](guide/http) when sending and receiving binary data
</td>
<td>
[Typed&nbsp;Array](guide/browser-support#typedarray) <br>[Blob](guide/browser-support#blob)<br>[FormData](guide/browser-support#formdata)
[Typed&nbsp;Array](guide/browser-support#typedarray)<br>
[Blob](guide/browser-support#blob)<br>
[FormData](guide/browser-support#formdata)
</td>
<td>
@ -405,7 +406,7 @@ Here are the features which may require additional polyfills:
### Suggested polyfills ##
Below are the polyfills which are used to test the framework itself. They are a good starting point for an application.
Below are the polyfills which are used to test the framework itself. They are a good starting point for an application.
<table>
@ -542,5 +543,5 @@ Below are the polyfills which are used to test the framework itself. They are a
\* Figures are for minified and gzipped code,
\* Figures are for minified and gzipped code,
computed with the <a href="http://closure-compiler.appspot.com/home">closure compiler</a>.

View File

@ -27,12 +27,12 @@ Revised samples are more clear and cover all topics discussed.
## NEW: Samples re-structured with `src/` folder (2017-02-02)
All documentation samples have been realigned with the default folder structure of the Angular CLI.
That's a step along the road to basing the sample in the Angular CLI.
But it's also good in its own right.
But it's also good in its own right.
It helps clearly separate app code from setup and configuration files.
All samples now have a `src/` folder at the project root.
The former `app/` folder moves under `src/`.
Read about moving your existing project to this structure in
The former `app/` folder moves under `src/`.
Read about moving your existing project to this structure in
<a href="https://github.com/angular/quickstart#updating-to-a-newer-version-of-the-quickstart-repo" target="Migrating samples/quickstart app to the src folder">
the QuickStart repo update instructions</a>.
@ -48,8 +48,8 @@ Notably:
The new [**Reactive Forms**](guide/reactive-forms) guide explains how and why to build a "reactive form".
"Reactive Forms" are the code-based counterpart to the declarative "Template Driven" forms approach
introduced in the [Forms](guide/forms) guide.
Check it out before you decide how to add forms to your app.
Remember also that you can use both techniques in the same app,
Check it out before you decide how to add forms to your app.
Remember also that you can use both techniques in the same app,
choosing the approach that best fits each scenario.
## NEW: Deployment guide (2017-01-30)
@ -65,25 +65,25 @@ Revised samples are clearer and cover all topics discussed.
## Miscellaneous (2017-01-05)
* [Setup](guide/setup) guide:
added (optional) instructions on how to remove _non-essential_ files.
* [Setup](guide/setup) guide:
added (optional) instructions on how to remove _non-essential_ files.
* No longer consolidate RxJS operator imports in `rxjs-extensions` file; each file should import what it needs.
* All samples prepend template/style URLs with `./` as a best practice.
* [Style Guide](guide/styleguide): copy edits and revised rules.
## Router: more detail (2016-12-21)
Added more information to the [Router](guide/router) guide
Added more information to the [Router](guide/router) guide
including sections named outlets, wildcard routes, and preload strategies.
## HTTP: how to set default request headers (and other request options) (2016-12-14)
Added section on how to set default request headers (and other request options) to
[HTTP](guide/http#override-default-request-options) guide.
Added section on how to set default request headers (and other request options) to
HTTP guide.
## Testing: added component test plunkers (2016-12-02)
Added two plunkers that each test _one simple component_ so you can write a component test plunker of your own: <live-example name="setup" plnkr="quickstart-specs">one</live-example> for the QuickStart seed's `AppComponent` and <live-example name="testing" plnkr="banner-specs">another</live-example> for the Testing guide's `BannerComponent`.
Added two plunkers that each test _one simple component_ so you can write a component test plunker of your own: <live-example name="setup" plnkr="quickstart-specs">one</live-example> for the QuickStart seed's `AppComponent` and <live-example name="testing" plnkr="banner-specs">another</live-example> for the Testing guide's `BannerComponent`.
Linked to these plunkers in [Testing](guide/testing#live-examples) and [Setup anatomy](guide/setup-systemjs-anatomy) guides.
## Internationalization: pluralization and _select_ (2016-11-30)
@ -112,15 +112,15 @@ Docs and code samples updated and tested with Angular v.2.2.0.
## UPDATE: NgUpgrade Guide for the AOT friendly _upgrade/static_ module (2016-11-14)
The updated [NgUpgrade Guide](guide/upgrade) guide covers the
new AOT friendly `upgrade/static` module
The updated [NgUpgrade Guide](guide/upgrade) guide covers the
new AOT friendly `upgrade/static` module
released in v.2.2.0, which is the recommended
facility for migrating from AngularJS to Angular.
The documentation for the version prior to v.2.2.0 has been removed.
## ES6 described in "TypeScript to JavaScript" (2016-11-14)
The updated [TypeScript to JavaScript](guide/ts-to-js) guide
The updated [TypeScript to JavaScript](guide/ts-to-js) guide
now explains how to write apps in ES6/7
by translating the common idioms in the TypeScript documentation examples
(and elsewhere on the web) to ES6/7 and ES5.
@ -156,7 +156,7 @@ in the `in-memory-web-api` repo.
The router can lazily _preload_ modules _after_ the app starts and
_before_ the user navigates to them for improved perceived performance.
New `:enter` and `:leave` aliases make animation more natural.
New `:enter` and `:leave` aliases make animation more natural.
## Sync with Angular v.2.1.0 (2016-10-12)
@ -176,11 +176,11 @@ Docs and code samples updated and tested with Angular v.2.0.2.
## "Routing and Navigation" guide with the _Router Module_ (2016-10-5)
The [Routing and Navigation](guide/router) guide now locates route configuration
in a _Routing Module_.
in a _Routing Module_.
The _Routing Module_ replaces the previous _routing object_ involving the `ModuleWithProviders`.
All guided samples with routing use the _Routing Module_ and prose content has been updated,
most conspicuously in the
most conspicuously in the
[NgModule](guide/ngmodule) guide and [NgModule FAQ](guide/ngmodule-faq) guide.
## New "Internationalization" guide (2016-09-30)
@ -194,7 +194,7 @@ Many samples use the `angular-in-memory-web-api` to simulate a remote server.
This library is also useful to you during early development before you have a server to talk to.
The package name was changed from "angular2-in-memory-web-api" which is still frozen-in-time on npm.
The new "angular-in-memory-web-api" has new features.
The new "angular-in-memory-web-api" has new features.
<a href="https://github.com/angular/in-memory-web-api/blob/master/README.md">Read about them on github</a>.
## "Style Guide" with _NgModules_ (2016-09-27)
@ -215,5 +215,5 @@ modules with SystemJS as the samples currently do.
## "Lifecycle Hooks" guide simplified (2016-09-24)
The [Lifecycle Hooks](guide/lifecycle-hooks) guide is shorter, simpler, and
The [Lifecycle Hooks](guide/lifecycle-hooks) guide is shorter, simpler, and
draws more attention to the order in which Angular calls the hooks.

View File

@ -1,4 +1,4 @@
# Cheat Sheet
<h1 class="no-toc">Cheat Sheet</h1>
<div id="cheatsheet">
<table class="is-full-width is-fixed-layout">
@ -23,28 +23,28 @@
</th>
</tr>
<tr>
<td><code>@<b>NgModule</b>({&nbsp;declarations:&nbsp;...,&nbsp;imports:&nbsp;...,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exports:&nbsp;...,&nbsp;providers:&nbsp;...,&nbsp;bootstrap:&nbsp;...})<br>class&nbsp;MyModule&nbsp;{}</code></td>
<td><code>@<b>NgModule</b>({ declarations: ..., imports: ...,<br> exports: ..., providers: ..., bootstrap: ...})<br>class MyModule {}</code></td>
<td><p>Defines a module that contains components, directives, pipes, and providers.</p>
</td>
</tr><tr>
<td><code><b>declarations:</b>&nbsp;[MyRedComponent,&nbsp;MyBlueComponent,&nbsp;MyDatePipe]</code></td>
<td><code><b>declarations:</b> [MyRedComponent, MyBlueComponent, MyDatePipe]</code></td>
<td><p>List of components, directives, and pipes that belong to this module.</p>
</td>
</tr><tr>
<td><code><b>imports:</b>&nbsp;[BrowserModule,&nbsp;SomeOtherModule]</code></td>
<td><code><b>imports:</b> [BrowserModule, SomeOtherModule]</code></td>
<td><p>List of modules to import into this module. Everything from the imported modules
is available to <code>declarations</code> of this module.</p>
</td>
</tr><tr>
<td><code><b>exports:</b>&nbsp;[MyRedComponent,&nbsp;MyDatePipe]</code></td>
<td><code><b>exports:</b> [MyRedComponent, MyDatePipe]</code></td>
<td><p>List of components, directives, and pipes visible to modules that import this module.</p>
</td>
</tr><tr>
<td><code><b>providers:</b>&nbsp;[MyService,&nbsp;{&nbsp;provide:&nbsp;...&nbsp;}]</code></td>
<td><code><b>providers:</b> [MyService, { provide: ... }]</code></td>
<td><p>List of dependency injection providers visible both to the contents of this module and to importers of this module.</p>
</td>
</tr><tr>
<td><code><b>bootstrap:</b>&nbsp;[MyAppComponent]</code></td>
<td><code><b>bootstrap:</b> [MyAppComponent]</code></td>
<td><p>List of components to bootstrap when this module is bootstrapped.</p>
</td>
</tr>
@ -56,61 +56,61 @@ is available to <code>declarations</code> of this module.</p>
<th></th>
</tr>
<tr>
<td><code>&lt;input&nbsp;<b>[value]</b>="firstName"&gt;</code></td>
<td><code>&lt;input <b>[value]</b>="firstName"&gt;</code></td>
<td><p>Binds property <code>value</code> to the result of expression <code>firstName</code>.</p>
</td>
</tr><tr>
<td><code>&lt;div&nbsp;<b>[attr.role]</b>="myAriaRole"&gt;</code></td>
<td><code>&lt;div <b>[attr.role]</b>="myAriaRole"&gt;</code></td>
<td><p>Binds attribute <code>role</code> to the result of expression <code>myAriaRole</code>.</p>
</td>
</tr><tr>
<td><code>&lt;div&nbsp;<b>[class.extra-sparkle]</b>="isDelightful"&gt;</code></td>
<td><code>&lt;div <b>[class.extra-sparkle]</b>="isDelightful"&gt;</code></td>
<td><p>Binds the presence of the CSS class <code>extra-sparkle</code> on the element to the truthiness of the expression <code>isDelightful</code>.</p>
</td>
</tr><tr>
<td><code>&lt;div&nbsp;<b>[style.width.px]</b>="mySize"&gt;</code></td>
<td><code>&lt;div <b>[style.width.px]</b>="mySize"&gt;</code></td>
<td><p>Binds style property <code>width</code> to the result of expression <code>mySize</code> in pixels. Units are optional.</p>
</td>
</tr><tr>
<td><code>&lt;button&nbsp;<b>(click)</b>="readRainbow($event)"&gt;</code></td>
<td><code>&lt;button <b>(click)</b>="readRainbow($event)"&gt;</code></td>
<td><p>Calls method <code>readRainbow</code> when a click event is triggered on this button element (or its children) and passes in the event object.</p>
</td>
</tr><tr>
<td><code>&lt;div&nbsp;title="Hello&nbsp;<b>{{ponyName}}</b>"&gt;</code></td>
<td><code>&lt;div title="Hello <b>{{ponyName}}</b>"&gt;</code></td>
<td><p>Binds a property to an interpolated string, for example, "Hello Seabiscuit". Equivalent to:
<code>&lt;div [title]="'Hello ' + ponyName"&gt;</code></p>
</td>
</tr><tr>
<td><code>&lt;p&gt;Hello&nbsp;<b>{{ponyName}}</b>&lt;/p&gt;</code></td>
<td><code>&lt;p&gt;Hello <b>{{ponyName}}</b>&lt;/p&gt;</code></td>
<td><p>Binds text content to an interpolated string, for example, "Hello Seabiscuit".</p>
</td>
</tr><tr>
<td><code>&lt;my-cmp&nbsp;<b>[(title)]</b>="name"&gt;</code></td>
<td><code>&lt;my-cmp <b>[(title)]</b>="name"&gt;</code></td>
<td><p>Sets up two-way data binding. Equivalent to: <code>&lt;my-cmp [title]="name" (titleChange)="name=$event"&gt;</code></p>
</td>
</tr><tr>
<td><code>&lt;video&nbsp;<b>#movieplayer</b>&nbsp;...&gt;<br>&nbsp;&nbsp;&lt;button&nbsp;<b>(click)</b>="movieplayer.play()"&gt;<br>&lt;/video&gt;</code></td>
<td><code>&lt;video <b>#movieplayer</b> ...&gt;<br> &lt;button <b>(click)</b>="movieplayer.play()"&gt;<br>&lt;/video&gt;</code></td>
<td><p>Creates a local variable <code>movieplayer</code> that provides access to the <code>video</code> element instance in data-binding and event-binding expressions in the current template.</p>
</td>
</tr><tr>
<td><code>&lt;p&nbsp;<b>*myUnless</b>="myExpression"&gt;...&lt;/p&gt;</code></td>
<td><code>&lt;p <b>*myUnless</b>="myExpression"&gt;...&lt;/p&gt;</code></td>
<td><p>The <code>*</code> symbol turns the current element into an embedded template. Equivalent to:
<code>&lt;ng-template [myUnless]="myExpression"&gt;&lt;p&gt;...&lt;/p&gt;&lt;/ng-template&gt;</code></p>
</td>
</tr><tr>
<td><code>&lt;p&gt;Card&nbsp;No.:&nbsp;<b>{{cardNumber&nbsp;|&nbsp;myCardNumberFormatter}}</b>&lt;/p&gt;</code></td>
<td><code>&lt;p&gt;Card No.: <b>{{cardNumber | myCardNumberFormatter}}</b>&lt;/p&gt;</code></td>
<td><p>Transforms the current value of expression <code>cardNumber</code> via the pipe called <code>myCardNumberFormatter</code>.</p>
</td>
</tr><tr>
<td><code>&lt;p&gt;Employer:&nbsp;<b>{{employer?.companyName}}</b>&lt;/p&gt;</code></td>
<td><code>&lt;p&gt;Employer: <b>{{employer?.companyName}}</b>&lt;/p&gt;</code></td>
<td><p>The safe navigation operator (<code>?</code>) means that the <code>employer</code> field is optional and if <code>undefined</code>, the rest of the expression should be ignored.</p>
</td>
</tr><tr>
<td><code>&lt;<b>svg:</b>rect&nbsp;x="0"&nbsp;y="0"&nbsp;width="100"&nbsp;height="100"/&gt;</code></td>
<td><code>&lt;<b>svg:</b>rect x="0" y="0" width="100" height="100"/&gt;</code></td>
<td><p>An SVG snippet template needs an <code>svg:</code> prefix on its root element to disambiguate the SVG element from an HTML component.</p>
</td>
</tr><tr>
<td><code>&lt;<b>svg</b>&gt;<br>&nbsp;&nbsp;&lt;rect&nbsp;x="0"&nbsp;y="0"&nbsp;width="100"&nbsp;height="100"/&gt;<br>&lt;/<b>svg</b>&gt;</code></td>
<td><code>&lt;<b>svg</b>&gt;<br> &lt;rect x="0" y="0" width="100" height="100"/&gt;<br>&lt;/<b>svg</b>&gt;</code></td>
<td><p>An <code>&lt;svg&gt;</code> root element is detected as an SVG element automatically, without the prefix.</p>
</td>
</tr>
@ -124,19 +124,19 @@ is available to <code>declarations</code> of this module.</p>
</th>
</tr>
<tr>
<td><code>&lt;section&nbsp;<b>*ngIf</b>="showSection"&gt;</code></td>
<td><code>&lt;section <b>*ngIf</b>="showSection"&gt;</code></td>
<td><p>Removes or recreates a portion of the DOM tree based on the <code>showSection</code> expression.</p>
</td>
</tr><tr>
<td><code>&lt;li&nbsp;<b>*ngFor</b>="let&nbsp;item&nbsp;of&nbsp;list"&gt;</code></td>
<td><code>&lt;li <b>*ngFor</b>="let item of list"&gt;</code></td>
<td><p>Turns the li element and its contents into a template, and uses that to instantiate a view for each item in list.</p>
</td>
</tr><tr>
<td><code>&lt;div&nbsp;<b>[ngSwitch]</b>="conditionExpression"&gt;<br>&nbsp;&nbsp;&lt;ng-template&nbsp;<b>[<b>ngSwitchCase</b>]</b>="case1Exp"&gt;...&lt;/ng-template&gt;<br>&nbsp;&nbsp;&lt;ng-template&nbsp;<b>ngSwitchCase</b>="case2LiteralString"&gt;...&lt;/ng-template&gt;<br>&nbsp;&nbsp;&lt;ng-template&nbsp;<b>ngSwitchDefault</b>&gt;...&lt;/ng-template&gt;<br>&lt;/div&gt;</code></td>
<td><code>&lt;div <b>[ngSwitch]</b>="conditionExpression"&gt;<br> &lt;ng-template <b>[<b>ngSwitchCase</b>]</b>="case1Exp"&gt;...&lt;/ng-template&gt;<br> &lt;ng-template <b>ngSwitchCase</b>="case2LiteralString"&gt;...&lt;/ng-template&gt;<br> &lt;ng-template <b>ngSwitchDefault</b>&gt;...&lt;/ng-template&gt;<br>&lt;/div&gt;</code></td>
<td><p>Conditionally swaps the contents of the div by selecting one of the embedded templates based on the current value of <code>conditionExpression</code>.</p>
</td>
</tr><tr>
<td><code>&lt;div&nbsp;<b>[ngClass]</b>="{'active':&nbsp;isActive,&nbsp;'disabled':&nbsp;isDisabled}"&gt;</code></td>
<td><code>&lt;div <b>[ngClass]</b>="{'active': isActive, 'disabled': isDisabled}"&gt;</code></td>
<td><p>Binds the presence of CSS classes on the element to the truthiness of the associated map values. The right-hand expression should return {class-name: true/false} map.</p>
</td>
</tr>
@ -150,7 +150,7 @@ is available to <code>declarations</code> of this module.</p>
</th>
</tr>
<tr>
<td><code>&lt;input&nbsp;<b>[(ngModel)]</b>="userName"&gt;</code></td>
<td><code>&lt;input <b>[(ngModel)]</b>="userName"&gt;</code></td>
<td><p>Provides two-way data-binding, parsing, and validation for form controls.</p>
</td>
</tr>
@ -164,19 +164,19 @@ is available to <code>declarations</code> of this module.</p>
</th>
</tr>
<tr>
<td><code><b>@Component({...})</b><br>class&nbsp;MyComponent()&nbsp;{}</code></td>
<td><code><b>@Component({...})</b><br>class MyComponent() {}</code></td>
<td><p>Declares that a class is a component and provides metadata about the component.</p>
</td>
</tr><tr>
<td><code><b>@Directive({...})</b><br>class&nbsp;MyDirective()&nbsp;{}</code></td>
<td><code><b>@Directive({...})</b><br>class MyDirective() {}</code></td>
<td><p>Declares that a class is a directive and provides metadata about the directive.</p>
</td>
</tr><tr>
<td><code><b>@Pipe({...})</b><br>class&nbsp;MyPipe()&nbsp;{}</code></td>
<td><code><b>@Pipe({...})</b><br>class MyPipe() {}</code></td>
<td><p>Declares that a class is a pipe and provides metadata about the pipe.</p>
</td>
</tr><tr>
<td><code><b>@Injectable()</b><br>class&nbsp;MyService()&nbsp;{}</code></td>
<td><code><b>@Injectable()</b><br>class MyService() {}</code></td>
<td><p>Declares that a class has dependencies that should be injected into the constructor when the dependency injector is creating an instance of this class.
</p>
</td>
@ -191,13 +191,13 @@ is available to <code>declarations</code> of this module.</p>
</th>
</tr>
<tr>
<td><code><b>selector:</b>&nbsp;'.cool-button:not(a)'</code></td>
<td><code><b>selector:</b> '.cool-button:not(a)'</code></td>
<td><p>Specifies a CSS selector that identifies this directive within a template. Supported selectors include <code>element</code>,
<code>[attribute]</code>, <code>.class</code>, and <code>:not()</code>.</p>
<p>Does not support parent-child relationship selectors.</p>
</td>
</tr><tr>
<td><code><b>providers:</b>&nbsp;[MyService,&nbsp;{&nbsp;provide:&nbsp;...&nbsp;}]</code></td>
<td><code><b>providers:</b> [MyService, { provide: ... }]</code></td>
<td><p>List of dependency injection providers for this directive and its children.</p>
</td>
</tr>
@ -212,19 +212,19 @@ so the <code>@Directive</code> configuration applies to components as well</p>
</th>
</tr>
<tr>
<td><code><b>moduleId:</b>&nbsp;module.id</code></td>
<td><code><b>moduleId:</b> module.id</code></td>
<td><p>If set, the <code>templateUrl</code> and <code>styleUrl</code> are resolved relative to the component.</p>
</td>
</tr><tr>
<td><code><b>viewProviders:</b>&nbsp;[MyService,&nbsp;{&nbsp;provide:&nbsp;...&nbsp;}]</code></td>
<td><code><b>viewProviders:</b> [MyService, { provide: ... }]</code></td>
<td><p>List of dependency injection providers scoped to this component's view.</p>
</td>
</tr><tr>
<td><code><b>template:</b>&nbsp;'Hello&nbsp;{{name}}'<br><b>templateUrl:</b>&nbsp;'my-component.html'</code></td>
<td><code><b>template:</b> 'Hello {{name}}'<br><b>templateUrl:</b> 'my-component.html'</code></td>
<td><p>Inline template or external template URL of the component's view.</p>
</td>
</tr><tr>
<td><code><b>styles:</b>&nbsp;['.primary&nbsp;{color:&nbsp;red}']<br><b>styleUrls:</b>&nbsp;['my-component.css']</code></td>
<td><code><b>styles:</b> ['.primary {color: red}']<br><b>styleUrls:</b> ['my-component.css']</code></td>
<td><p>List of inline CSS styles or external stylesheet URLs for styling the components view.</p>
</td>
</tr>
@ -238,36 +238,36 @@ so the <code>@Directive</code> configuration applies to components as well</p>
</th>
</tr>
<tr>
<td><code><b>@Input()</b>&nbsp;myProperty;</code></td>
<td><code><b>@Input()</b> myProperty;</code></td>
<td><p>Declares an input property that you can update via property binding (example:
<code>&lt;my-cmp [myProperty]="someExpression"&gt;</code>).</p>
</td>
</tr><tr>
<td><code><b>@Output()</b>&nbsp;myEvent&nbsp;=&nbsp;new&nbsp;EventEmitter();</code></td>
<td><code><b>@Output()</b> myEvent = new EventEmitter();</code></td>
<td><p>Declares an output property that fires events that you can subscribe to with an event binding (example: <code>&lt;my-cmp (myEvent)="doSomething()"&gt;</code>).</p>
</td>
</tr><tr>
<td><code><b>@HostBinding('class.valid')</b>&nbsp;isValid;</code></td>
<td><code><b>@HostBinding('class.valid')</b> isValid;</code></td>
<td><p>Binds a host element property (here, the CSS class <code>valid</code>) to a directive/component property (<code>isValid</code>).</p>
</td>
</tr><tr>
<td><code><b>@HostListener('click',&nbsp;['$event'])</b>&nbsp;onClick(e)&nbsp;{...}</code></td>
<td><code><b>@HostListener('click', ['$event'])</b> onClick(e) {...}</code></td>
<td><p>Subscribes to a host element event (<code>click</code>) with a directive/component method (<code>onClick</code>), optionally passing an argument (<code>$event</code>).</p>
</td>
</tr><tr>
<td><code><b>@ContentChild(myPredicate)</b>&nbsp;myChildComponent;</code></td>
<td><code><b>@ContentChild(myPredicate)</b> myChildComponent;</code></td>
<td><p>Binds the first result of the component content query (<code>myPredicate</code>) to a property (<code>myChildComponent</code>) of the class.</p>
</td>
</tr><tr>
<td><code><b>@ContentChildren(myPredicate)</b>&nbsp;myChildComponents;</code></td>
<td><code><b>@ContentChildren(myPredicate)</b> myChildComponents;</code></td>
<td><p>Binds the results of the component content query (<code>myPredicate</code>) to a property (<code>myChildComponents</code>) of the class.</p>
</td>
</tr><tr>
<td><code><b>@ViewChild(myPredicate)</b>&nbsp;myChildComponent;</code></td>
<td><code><b>@ViewChild(myPredicate)</b> myChildComponent;</code></td>
<td><p>Binds the first result of the component view query (<code>myPredicate</code>) to a property (<code>myChildComponent</code>) of the class. Not available for directives.</p>
</td>
</tr><tr>
<td><code><b>@ViewChildren(myPredicate)</b>&nbsp;myChildComponents;</code></td>
<td><code><b>@ViewChildren(myPredicate)</b> myChildComponents;</code></td>
<td><p>Binds the results of the component view query (<code>myPredicate</code>) to a property (<code>myChildComponents</code>) of the class. Not available for directives.</p>
</td>
</tr>
@ -281,39 +281,39 @@ so the <code>@Directive</code> configuration applies to components as well</p>
</th>
</tr>
<tr>
<td><code><b>constructor(myService:&nbsp;MyService,&nbsp;...)</b>&nbsp;{&nbsp;...&nbsp;}</code></td>
<td><code><b>constructor(myService: MyService, ...)</b> { ... }</code></td>
<td><p>Called before any other lifecycle hook. Use it to inject dependencies, but avoid any serious work here.</p>
</td>
</tr><tr>
<td><code><b>ngOnChanges(changeRecord)</b>&nbsp;{&nbsp;...&nbsp;}</code></td>
<td><code><b>ngOnChanges(changeRecord)</b> { ... }</code></td>
<td><p>Called after every change to input properties and before processing content or child views.</p>
</td>
</tr><tr>
<td><code><b>ngOnInit()</b>&nbsp;{&nbsp;...&nbsp;}</code></td>
<td><code><b>ngOnInit()</b> { ... }</code></td>
<td><p>Called after the constructor, initializing input properties, and the first call to <code>ngOnChanges</code>.</p>
</td>
</tr><tr>
<td><code><b>ngDoCheck()</b>&nbsp;{&nbsp;...&nbsp;}</code></td>
<td><code><b>ngDoCheck()</b> { ... }</code></td>
<td><p>Called every time that the input properties of a component or a directive are checked. Use it to extend change detection by performing a custom check.</p>
</td>
</tr><tr>
<td><code><b>ngAfterContentInit()</b>&nbsp;{&nbsp;...&nbsp;}</code></td>
<td><code><b>ngAfterContentInit()</b> { ... }</code></td>
<td><p>Called after <code>ngOnInit</code> when the component's or directive's content has been initialized.</p>
</td>
</tr><tr>
<td><code><b>ngAfterContentChecked()</b>&nbsp;{&nbsp;...&nbsp;}</code></td>
<td><code><b>ngAfterContentChecked()</b> { ... }</code></td>
<td><p>Called after every check of the component's or directive's content.</p>
</td>
</tr><tr>
<td><code><b>ngAfterViewInit()</b>&nbsp;{&nbsp;...&nbsp;}</code></td>
<td><code><b>ngAfterViewInit()</b> { ... }</code></td>
<td><p>Called after <code>ngAfterContentInit</code> when the component's view has been initialized. Applies to components only.</p>
</td>
</tr><tr>
<td><code><b>ngAfterViewChecked()</b>&nbsp;{&nbsp;...&nbsp;}</code></td>
<td><code><b>ngAfterViewChecked()</b> { ... }</code></td>
<td><p>Called after every check of the component's view. Applies to components only.</p>
</td>
</tr><tr>
<td><code><b>ngOnDestroy()</b>&nbsp;{&nbsp;...&nbsp;}</code></td>
<td><code><b>ngOnDestroy()</b> { ... }</code></td>
<td><p>Called once, before the instance is destroyed.</p>
</td>
</tr>
@ -325,15 +325,15 @@ so the <code>@Directive</code> configuration applies to components as well</p>
<th></th>
</tr>
<tr>
<td><code>{&nbsp;<b>provide</b>:&nbsp;MyService,&nbsp;<b>useClass</b>:&nbsp;MyMockService&nbsp;}</code></td>
<td><code>{ <b>provide</b>: MyService, <b>useClass</b>: MyMockService }</code></td>
<td><p>Sets or overrides the provider for <code>MyService</code> to the <code>MyMockService</code> class.</p>
</td>
</tr><tr>
<td><code>{&nbsp;<b>provide</b>:&nbsp;MyService,&nbsp;<b>useFactory</b>:&nbsp;myFactory&nbsp;}</code></td>
<td><code>{ <b>provide</b>: MyService, <b>useFactory</b>: myFactory }</code></td>
<td><p>Sets or overrides the provider for <code>MyService</code> to the <code>myFactory</code> factory function.</p>
</td>
</tr><tr>
<td><code>{&nbsp;<b>provide</b>:&nbsp;MyValue,&nbsp;<b>useValue</b>:&nbsp;41&nbsp;}</code></td>
<td><code>{ <b>provide</b>: MyValue, <b>useValue</b>: 41 }</code></td>
<td><p>Sets or overrides the provider for <code>MyValue</code> to the value <code>41</code>.</p>
</td>
</tr>
@ -347,39 +347,39 @@ so the <code>@Directive</code> configuration applies to components as well</p>
</th>
</tr>
<tr>
<td><code>const&nbsp;routes:&nbsp;<b>Routes</b>&nbsp;=&nbsp;[<br>&nbsp;&nbsp;{&nbsp;path:&nbsp;'',&nbsp;component:&nbsp;HomeComponent&nbsp;},<br>&nbsp;&nbsp;{&nbsp;path:&nbsp;'path/:routeParam',&nbsp;component:&nbsp;MyComponent&nbsp;},<br>&nbsp;&nbsp;{&nbsp;path:&nbsp;'staticPath',&nbsp;component:&nbsp;...&nbsp;},<br>&nbsp;&nbsp;{&nbsp;path:&nbsp;'**',&nbsp;component:&nbsp;...&nbsp;},<br>&nbsp;&nbsp;{&nbsp;path:&nbsp;'oldPath',&nbsp;redirectTo:&nbsp;'/staticPath'&nbsp;},<br>&nbsp;&nbsp;{&nbsp;path:&nbsp;...,&nbsp;component:&nbsp;...,&nbsp;data:&nbsp;{&nbsp;message:&nbsp;'Custom'&nbsp;}&nbsp;}<br>]);<br><br>const&nbsp;routing&nbsp;=&nbsp;RouterModule.forRoot(routes);</code></td>
<td><code>const routes: <b>Routes</b> = [<br> { path: '', component: HomeComponent },<br> { path: 'path/:routeParam', component: MyComponent },<br> { path: 'staticPath', component: ... },<br> { path: '**', component: ... },<br> { path: 'oldPath', redirectTo: '/staticPath' },<br> { path: ..., component: ..., data: { message: 'Custom' } }<br>]);<br><br>const routing = RouterModule.forRoot(routes);</code></td>
<td><p>Configures routes for the application. Supports static, parameterized, redirect, and wildcard routes. Also supports custom route data and resolve.</p>
</td>
</tr><tr>
<td><code><br>&lt;<b>router-outlet</b>&gt;&lt;/<b>router-outlet</b>&gt;<br>&lt;<b>router-outlet</b>&nbsp;name="aux"&gt;&lt;/<b>router-outlet</b>&gt;<br></code></td>
<td><code><br>&lt;<b>router-outlet</b>&gt;&lt;/<b>router-outlet</b>&gt;<br>&lt;<b>router-outlet</b> name="aux"&gt;&lt;/<b>router-outlet</b>&gt;<br></code></td>
<td><p>Marks the location to load the component of the active route.</p>
</td>
</tr><tr>
<td><code><br>&lt;a&nbsp;routerLink="/path"&gt;<br>&lt;a&nbsp;<b>[routerLink]</b>="[&nbsp;'/path',&nbsp;routeParam&nbsp;]"&gt;<br>&lt;a&nbsp;<b>[routerLink]</b>="[&nbsp;'/path',&nbsp;{&nbsp;matrixParam:&nbsp;'value'&nbsp;}&nbsp;]"&gt;<br>&lt;a&nbsp;<b>[routerLink]</b>="[&nbsp;'/path'&nbsp;]"&nbsp;[queryParams]="{&nbsp;page:&nbsp;1&nbsp;}"&gt;<br>&lt;a&nbsp;<b>[routerLink]</b>="[&nbsp;'/path'&nbsp;]"&nbsp;fragment="anchor"&gt;<br></code></td>
<td><code><br>&lt;a routerLink="/path"&gt;<br>&lt;a <b>[routerLink]</b>="[ '/path', routeParam ]"&gt;<br>&lt;a <b>[routerLink]</b>="[ '/path', { matrixParam: 'value' } ]"&gt;<br>&lt;a <b>[routerLink]</b>="[ '/path' ]" [queryParams]="{ page: 1 }"&gt;<br>&lt;a <b>[routerLink]</b>="[ '/path' ]" fragment="anchor"&gt;<br></code></td>
<td><p>Creates a link to a different view based on a route instruction consisting of a route path, required and optional parameters, query parameters, and a fragment. To navigate to a root route, use the <code>/</code> prefix; for a child route, use the <code>./</code>prefix; for a sibling or parent, use the <code>../</code> prefix.</p>
</td>
</tr><tr>
<td><code>&lt;a&nbsp;[routerLink]="[&nbsp;'/path'&nbsp;]"&nbsp;routerLinkActive="active"&gt;</code></td>
<td><code>&lt;a [routerLink]="[ '/path' ]" routerLinkActive="active"&gt;</code></td>
<td><p>The provided classes are added to the element when the <code>routerLink</code> becomes the current active route.</p>
</td>
</tr><tr>
<td><code>class&nbsp;<b>CanActivate</b>Guard&nbsp;implements&nbsp;<b>CanActivate</b>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;canActivate(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;route:&nbsp;ActivatedRouteSnapshot,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state:&nbsp;RouterStateSnapshot<br>&nbsp;&nbsp;&nbsp;&nbsp;):&nbsp;Observable&lt;boolean&gt;|Promise&lt;boolean&gt;|boolean&nbsp;{&nbsp;...&nbsp;}<br>}<br><br>{&nbsp;path:&nbsp;...,&nbsp;canActivate:&nbsp;[<b>CanActivate</b>Guard]&nbsp;}</code></td>
<td><code>class <b>CanActivate</b>Guard implements <b>CanActivate</b> {<br> canActivate(<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable&lt;boolean&gt;|Promise&lt;boolean&gt;|boolean { ... }<br>}<br><br>{ path: ..., canActivate: [<b>CanActivate</b>Guard] }</code></td>
<td><p>An interface for defining a class that the router should call first to determine if it should activate this component. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
</td>
</tr><tr>
<td><code>class&nbsp;<b>CanDeactivate</b>Guard&nbsp;implements&nbsp;<b>CanDeactivate</b>&lt;T&gt;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;canDeactivate(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;component:&nbsp;T,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;route:&nbsp;ActivatedRouteSnapshot,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state:&nbsp;RouterStateSnapshot<br>&nbsp;&nbsp;&nbsp;&nbsp;):&nbsp;Observable&lt;boolean&gt;|Promise&lt;boolean&gt;|boolean&nbsp;{&nbsp;...&nbsp;}<br>}<br><br>{&nbsp;path:&nbsp;...,&nbsp;canDeactivate:&nbsp;[<b>CanDeactivate</b>Guard]&nbsp;}</code></td>
<td><code>class <b>CanDeactivate</b>Guard implements <b>CanDeactivate</b>&lt;T&gt; {<br> canDeactivate(<br> component: T,<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable&lt;boolean&gt;|Promise&lt;boolean&gt;|boolean { ... }<br>}<br><br>{ path: ..., canDeactivate: [<b>CanDeactivate</b>Guard] }</code></td>
<td><p>An interface for defining a class that the router should call first to determine if it should deactivate this component after a navigation. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
</td>
</tr><tr>
<td><code>class&nbsp;<b>CanActivateChild</b>Guard&nbsp;implements&nbsp;<b>CanActivateChild</b>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;canActivateChild(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;route:&nbsp;ActivatedRouteSnapshot,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state:&nbsp;RouterStateSnapshot<br>&nbsp;&nbsp;&nbsp;&nbsp;):&nbsp;Observable&lt;boolean&gt;|Promise&lt;boolean&gt;|boolean&nbsp;{&nbsp;...&nbsp;}<br>}<br><br>{&nbsp;path:&nbsp;...,&nbsp;canActivateChild:&nbsp;[CanActivateGuard],<br>&nbsp;&nbsp;&nbsp;&nbsp;children:&nbsp;...&nbsp;}</code></td>
<td><code>class <b>CanActivateChild</b>Guard implements <b>CanActivateChild</b> {<br> canActivateChild(<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable&lt;boolean&gt;|Promise&lt;boolean&gt;|boolean { ... }<br>}<br><br>{ path: ..., canActivateChild: [CanActivateGuard],<br> children: ... }</code></td>
<td><p>An interface for defining a class that the router should call first to determine if it should activate the child route. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
</td>
</tr><tr>
<td><code>class&nbsp;<b>Resolve</b>Guard&nbsp;implements&nbsp;<b>Resolve</b>&lt;T&gt;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;resolve(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;route:&nbsp;ActivatedRouteSnapshot,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state:&nbsp;RouterStateSnapshot<br>&nbsp;&nbsp;&nbsp;&nbsp;):&nbsp;Observable&lt;any&gt;|Promise&lt;any&gt;|any&nbsp;{&nbsp;...&nbsp;}<br>}<br><br>{&nbsp;path:&nbsp;...,&nbsp;resolve:&nbsp;[<b>Resolve</b>Guard]&nbsp;}</code></td>
<td><code>class <b>Resolve</b>Guard implements <b>Resolve</b>&lt;T&gt; {<br> resolve(<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable&lt;any&gt;|Promise&lt;any&gt;|any { ... }<br>}<br><br>{ path: ..., resolve: [<b>Resolve</b>Guard] }</code></td>
<td><p>An interface for defining a class that the router should call first to resolve route data before rendering the route. Should return a value or an Observable/Promise that resolves to a value.</p>
</td>
</tr><tr>
<td><code>class&nbsp;<b>CanLoad</b>Guard&nbsp;implements&nbsp;<b>CanLoad</b>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;canLoad(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;route:&nbsp;Route<br>&nbsp;&nbsp;&nbsp;&nbsp;):&nbsp;Observable&lt;boolean&gt;|Promise&lt;boolean&gt;|boolean&nbsp;{&nbsp;...&nbsp;}<br>}<br><br>{&nbsp;path:&nbsp;...,&nbsp;canLoad:&nbsp;[<b>CanLoad</b>Guard],&nbsp;loadChildren:&nbsp;...&nbsp;}</code></td>
<td><code>class <b>CanLoad</b>Guard implements <b>CanLoad</b> {<br> canLoad(<br> route: Route<br> ): Observable&lt;boolean&gt;|Promise&lt;boolean&gt;|boolean { ... }<br>}<br><br>{ path: ..., canLoad: [<b>CanLoad</b>Guard], loadChildren: ... }</code></td>
<td><p>An interface for defining a class that the router should call first to check if the lazy loaded module should be loaded. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
</td>
</tr>

View File

@ -29,7 +29,7 @@ import {HttpClientModule} from '@angular/common/http';
export class MyAppModule {}
```
Once you import `HttpClientModule` into your app module, you can inject `HttpClient`
Once you import `HttpClientModule` into your app module, you can inject `HttpClient`
into your components and services.
## Making a request for JSON data
@ -50,10 +50,13 @@ The `get()` method on `HttpClient` makes accessing this data straightforward.
```javascript
@Component(...)
export class MyComponent implements NgOnInit {
export class MyComponent implements OnInit {
results: string[];
// Inject HttpClient into your component or service.
constructor(private http: HttpClient) {}
ngOnInit(): void {
// Make the HTTP request:
this.http.get('/api/items').subscribe(data => {
@ -69,7 +72,7 @@ export class MyComponent implements NgOnInit {
In the above example, the `data['results']` field access stands out because you use bracket notation to access the results field. If you tried to write `data.results`, TypeScript would correctly complain that the `Object` coming back from HTTP does not have a `results` property. That's because while `HttpClient` parsed the JSON response into an `Object`, it doesn't know what shape that object is.
You can, however, tell `HttpClient` what type the response will be, which is recommended.
You can, however, tell `HttpClient` what type the response will be, which is recommended.
To do so, first you define an interface with the correct shape:
```javascript
@ -160,7 +163,7 @@ RxJS has a useful operator called `.retry()`, which automatically resubscribes t
First, import it:
```js
```js
import 'rxjs/add/operator/retry';
```
@ -194,7 +197,7 @@ In addition to fetching data from the server, `HttpClient` supports mutating req
### Making a POST request
One common operation is to POST data to a server; for example when submitting a form. The code for
One common operation is to POST data to a server; for example when submitting a form. The code for
sending a POST request is very similar to the code for GET:
```javascript
@ -258,22 +261,22 @@ The above sections detail how to use the basic HTTP functionality in `@angular/c
### Intercepting all requests or responses
A major feature of `@angular/common/http` is _interception_, the ability to declare interceptors which sit in between your application and the backend. When your application makes a request, interceptors transform it
A major feature of `@angular/common/http` is _interception_, the ability to declare interceptors which sit in between your application and the backend. When your application makes a request, interceptors transform it
before sending it to the server, and the interceptors can transform the response on its way back before your application sees it. This is useful for everything from authentication to logging.
#### Writing an interceptor
To implement an interceptor, you declare a class that implements `HttpInterceptor`, which
To implement an interceptor, you declare a class that implements `HttpInterceptor`, which
has a single `intercept()` method. Here is a simple interceptor which does nothing but forward the request through without altering it:
```javascript
import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest) from '@angular/common/http';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
@Injectable()
export class NoopInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(Req);
return next.handle(req);
}
}
```
@ -316,7 +319,7 @@ An interceptor must pass through all events that it does not understand or inten
##### Ordering
When you provide multiple interceptors in an application, Angular applies them in the order that you
When you provide multiple interceptors in an application, Angular applies them in the order that you
provided them.
##### Immutability
@ -332,10 +335,10 @@ If you have a need to mutate the request body, you need to copy the request body
Since requests are immutable, they cannot be modified directly. To mutate them, use `clone()`:
```javascript
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpError<any>> {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// This is a duplicate. It is exactly the same as the original.
const dupReq = req.clone();
// Change the URL and replace 'http://' with 'https://'
const secureReq = req.clone({url: req.url.replace('http://', 'https://')});
}
@ -349,15 +352,15 @@ A common use of interceptors is to set default headers on outgoing responses. Fo
```javascript
import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest) from '@angular/common/http';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private auth: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Get the auth header from the service.
const authHeader: this.auth.getAuthorizationHeader();
const authHeader = this.auth.getAuthorizationHeader();
// Clone the request to add the new header.
const authReq = req.clone({headers: req.headers.set('Authorization', authHeader)});
// Pass on the cloned request instead of the original request.
@ -387,15 +390,15 @@ import 'rxjs/add/operator/do';
export class TimingInterceptor implements HttpInterceptor {
constructor(private auth: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const elapsed = Date.now();
const started = Date.now();
return next
.handle(req)
.do(event => {
if (event instanceof HttpResponse) {
const time = Date.now() - started;
console.log(`Request for ${req.urlWithParams} took ${elapsed} ms.`);
const elapsed = Date.now() - started;
console.log(`Request for ${req.urlWithParams} took ${elapsed} ms.`);
}
});
}
@ -413,7 +416,7 @@ abstract class HttpCache {
* Returns a cached response, if any, or null if not present.
*/
abstract get(req: HttpRequest<any>): HttpResponse<any>|null;
/**
* Adds or updates the response in the cache.
*/
@ -427,14 +430,14 @@ An interceptor can apply this cache to outgoing requests.
@Injectable()
export class CachingInterceptor implements HttpInterceptor {
constructor(private cache: HttpCache) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Before doing anything, it's important to only cache GET requests.
// Skip this interceptor if the request method isn't GET.
if (req.method !== 'GET') {
return next.handle(req);
}
// First, check the cache to see if this request exists.
const cachedResponse = this.cache.get(req);
if (cachedResponse) {
@ -442,7 +445,7 @@ export class CachingInterceptor implements HttpInterceptor {
// the request to the next handler.
return Observable.of(cachedResponse);
}
// No cached response exists. Go to the network, and cache
// the response when it arrives.
return next.handle(req).do(event => {
@ -466,17 +469,17 @@ intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
if (req.method !== 'GET') {
return next.handle(req);
}
// This will be an Observable of the cached value if there is one,
// or an empty Observable otherwise. It starts out empty.
let maybeCachedResponse: Observable<HttpEvent<any>> = Observable.empty();
// Check the cache.
const cachedResponse = this.cache.get(req);
if (cachedResponse) {
maybeCachedResponse = Observable.of(cachedResponse);
}
// Create an Observable (but don't subscribe) that represents making
// the network request and caching the value.
const networkResponse = next.handle(req).do(event => {
@ -485,7 +488,7 @@ intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
this.cache.put(req, event);
}
});
// Now, combine the two and send the cached response first (if there is
// one), and the network response second.
return Observable.concat(maybeCachedResponse, networkResponse);
@ -506,7 +509,7 @@ const req = new HttpRequest('POST', '/upload/file', file, {
});
```
This option enables tracking of progress events. Remember, every progress event triggers
This option enables tracking of progress events. Remember, every progress event triggers
change detection, so only turn them on if you intend to actually update the UI on each event.
Next, make the request through the `request()` method of `HttpClient`. The result will be an Observable of events, just like with interceptors:
@ -529,11 +532,11 @@ http.request(req).subscribe(event => {
[Cross-Site Request Forgery (XSRF)](https://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by which the attacker can trick an authenticated user into unknowingly executing actions on your website. `HttpClient` supports a [common mechanism](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Cookie-to-Header_Token) used to prevent XSRF attacks. When performing HTTP requests, an interceptor reads a token from a cookie, by default `XSRF-TOKEN`, and sets it as an HTTP header, `X-XSRF-TOKEN`. Since only code that runs on your domain could read the cookie, the backend can be certain that the HTTP request came from your client application and not an attacker.
By default, an interceptor sends this cookie on all mutating requests (POST, etc.)
to relative URLs but not on GET/HEAD requests or
By default, an interceptor sends this cookie on all mutating requests (POST, etc.)
to relative URLs but not on GET/HEAD requests or
on requests with an absolute URL.
To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called `XSRF-TOKEN` on either the page load or the first GET request. On subsequent requests the server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be sure that only code running on your domain could have sent the request. The token must be unique for each user and must be verifiable by the server; this prevents the client from making up its own tokens. Set the token to a digest of your site's authentication
To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called `XSRF-TOKEN` on either the page load or the first GET request. On subsequent requests the server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be sure that only code running on your domain could have sent the request. The token must be unique for each user and must be verifiable by the server; this prevents the client from making up its own tokens. Set the token to a digest of your site's authentication
cookie with a salt for added security.
In order to prevent collisions in environments where multiple Angular apps share the same domain or subdomain, give each application a unique cookie name.
@ -595,23 +598,23 @@ it('expects a GET request', inject([HttpClient, HttpTestingController], (http: H
http
.get('/data')
.subscribe(data => expect(data['name']).toEqual('Test Data'));
// At this point, the request is pending, and no response has been
// sent. The next step is to expect that the request happened.
const req = httpMock.expectOne('/test');
const req = httpMock.expectOne('/data');
// If no request with that URL was made, or if multiple requests match,
// expectOne() would throw. However this test makes only one request to
// this URL, so it will match and return a mock request. The mock request
// can be used to deliver a response or make assertions against the
// request. In this case, the test asserts that the request is a GET.
expect(req.request.method).toEqual('GET');
// Next, fulfill the request by transmitting a response.
req.flush({name: 'Test Data'});
// Finally, assert that there are no outstanding requests.
mockHttp.verify();
httpMock.verify();
}));
```
@ -619,7 +622,7 @@ The last step, verifying that no requests remain outstanding, is common enough f
```javascript
afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
mockHttp.verify();
httpMock.verify();
}));
```
@ -628,7 +631,7 @@ afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
If matching by URL isn't sufficient, it's possible to implement your own matching function. For example, you could look for an outgoing request that has an Authorization header:
```javascript
const req = mockHttp.expectOne((req) => req.headers.has('Authorization'));
const req = httpMock.expectOne((req) => req.headers.has('Authorization'));
```
Just as with the `expectOne()` by URL in the test above, if 0 or 2+ requests match this expectation, it will throw.
@ -639,7 +642,7 @@ If you need to respond to duplicate requests in your test, use the `match()` API
```javascript
// Expect that 5 pings have been made and flush them.
const reqs = mockHttp.match('/ping');
const reqs = httpMock.match('/ping');
expect(reqs.length).toBe(5);
reqs.forEach(req => req.flush());
```

View File

@ -0,0 +1,176 @@
# Angular Language Service
The Angular Language Service is a way to get completions, errors,
hints, and navigation inside your Angular templates whether they
are external in an HTML file or embedded in annotations/decorators
in a string. The Angular Language Service autodetects that you are
opening an Angular file, reads your `tsconfig.json` file, finds all the
templates you have in your application, and then provides language
services for any templates that you open.
## Autocompletion
Autocompletion can speed up your development time by providing you with
contextual possibilities and hints as you type. This example shows
autocomplete in an interpolation. As you type it out,
you can hit tab to complete.
<figure>
<img src="generated/images/guide/language-service/language-completion.gif" alt="autocompletion">
</figure>
There are also completions within
elements. Any elements you have as a component selector will
show up in the completion list.
## Error checking
The Angular Language Service can also forewarn you of mistakes in your code.
In this example, Angular doesn't know what `orders` is or where it comes from.
<figure>
<img src="generated/images/guide/language-service/language-error.gif" alt="error checking">
</figure>
## Navigation
Navigation allows you to hover to
see where a component, directive, module, etc. is from and then
click and press F12 to go directly to its definition.
<figure>
<img src="generated/images/guide/language-service/language-navigation.gif" alt="navigation">
</figure>
## Angular Language Service in your editor
Angular Language Service is currently available for [Visual Studio Code](https://code.visualstudio.com/) and
[WebStorm](https://www.jetbrains.com/webstorm).
### Visual Studio Code
In Visual Studio Code, install Angular Language Service from the store,
which is accessible from the bottom icon on the left menu pane.
You can also use the VS Quick Open (⌘+P) to search for the extension. When you've opened it,
enter the following command:
```sh
ext install ng-template
```
Then click the install button to install the Angular Language Service.
### WebStorm
In webstorm, you have to install the language service as a dev dependency.
When Angular sees this dev dependency, it provides the
language service inside of WebStorm. Webstorm then gives you
colorization inside the template and autocomplete in addition to the Angular Language Service.
Here's the dev dependency
you need to have in `package.json`:
```json
devDependencies {
"@angular/language-service": "^4.0.0"
}
```
Then in the terminal window at the root of your project,
install the `devDependencies` with `npm` or `yarn`:
```sh
npm install
```
*OR*
```sh
yarn
```
*OR*
```sh
yarn install
```
### Sublime Text
In [Sublime Text](https://www.sublimetext.com/), you first need an extension to allow Typescript.
Install the latest version of typescript in a local `node_modules` directory:
```sh
npm install --save-dev typescript
```
Then install the Angular Language Service in the same location:
```sh
npm install --save-dev @angular/language-service
```
Starting with TypeScript 2.3, TypeScript has a language service plugin model that the language service can use.
Next, in your user preferences (`Cmd+,` or `Ctrl+,`), add:
```json
"typescript-tsdk": "<path to your folder>/node_modules/typescript/lib"
```
## Installing in your project
You can also install Angular Language Service in your project with the
following `npm` command:
```sh
npm install --save-dev @angular/language-service
```
Additionally, add the following to the `"compilerOptions"` section of
your project's `tsconfig.json`.
```json
"plugins": [
{"name": "@angular/language-service"}
]
```
Note that this only provides diagnostics and completions in `.ts`
files. You need a custom sublime plugin (or modifications to the current plugin)
for completions in HTML files.
## How the Language Service works
When you use an editor with a language service, there's an
editor process which starts a separate language process/service
to which it speaks through an [RPC](https://en.wikipedia.org/wiki/Remote_procedure_call).
Any time you type inside of the editor, it sends information to the other process to
track the state of your project. When you trigger a completion list within a template, the editor process first parses the template into an HTML AST, or [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree). Then the Angular compiler interprets
what module the template is part of, the scope you're in, and the component selector. Then it figures out where in the template AST your cursor is. When it determines the
context, it can then determine what the children can be.
It's a little more involved if you are in an interpolation. If you have an interpolation of `{{data.---}}` inside a `div` and need the completion list after `data.---`, the compiler can't use the HTML AST to find the answer. The HTML AST can only tell the compiler that there is some text with the characters "`{{data.---}}`". That's when the template parser produces an expression AST, which resides within the template AST. The Angular Language Services then looks at `data.---` within its context and asks the TypeScript Language Service what the members of data are. TypeScript then returns the list of possibilities.
For more in-depth information, see the
[Angular Language Service API](https://github.com/angular/angular/blob/master/packages/language-service/src/types.ts)
<hr>
## More on Information
For more information, see [Chuck Jazdzewski's presentation](https://www.youtube.com/watch?v=ez3R0Gi4z5A&t=368s) on the Angular Language
Service from [ng-conf](https://www.ng-conf.org/) 2017.

View File

@ -397,8 +397,7 @@ created under test or before you decide to display it.
Constructors should do no more than set the initial local variables to simple values.
An `ngOnInit()` is a good place for a component to fetch its initial data. The
[Tour of Heroes Tutorial](tutorial/toh-pt4#oninit) and [HTTP Client](guide/http#oninit)
guides show how.
[Tour of Heroes Tutorial](tutorial/toh-pt4#oninit) guide shows how.
Remember also that a directive's data-bound input properties are not set until _after construction_.

View File

@ -615,7 +615,7 @@ Once the application begins, the app root injector is closed to new providers.
Time passes and application logic triggers lazy loading of a module.
Angular must add the lazy-loaded module's providers to an injector somewhere.
It can't added them to the app root injector because that injector is closed to new providers.
It can't add them to the app root injector because that injector is closed to new providers.
So Angular creates a new child injector for the lazy-loaded module context.

View File

@ -163,7 +163,6 @@ without waiting for Angular updates.
***angular-in-memory-web-api***: An Angular-supported library that simulates a remote server's web api
without requiring an actual server or real HTTP calls.
Good for demos, samples, and early stage development (before you even have a server).
Read about it in the [HTTP Client](guide/http#in-mem-web-api) page.
***bootstrap***: [Bootstrap](http://getbootstrap.com/) is a popular HTML and CSS framework for designing responsive web apps.
Some of the samples improve their appearance with *bootstrap*.

View File

@ -1080,8 +1080,11 @@ To get access to the `FormArray` class, import it into `hero-detail.component.ts
To _work_ with a `FormArray` you do the following:
1. Define the items (`FormControls` or `FormGroups`) in the array.
1. Initialize the array with items created from data in the _data model_.
1. Add and remove items as the user requires.
In this guide, you define a `FormArray` for `Hero.addresses` and

View File

@ -255,11 +255,11 @@ During each navigation, the `Router` emits navigation events through the `Router
<tr>
<td>
<code>RouteConfigLoadStart</code>
<code>RouteConfigLoadEnd</code>
</td>
<td>
An [event](api/router/RouteConfigLoadStart) triggered after a route has been lazy loaded.
An [event](api/router/RouteConfigLoadEnd) triggered after a route has been lazy loaded.
</td>
</tr>
@ -1830,7 +1830,7 @@ Finally, you activate the observable with `subscribe` method and (re)set the com
#### _ParamMap_ API
The `ParamMap` API is inspired by the [URLSearchParams interface](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParamsOPut). It provides methods
The `ParamMap` API is inspired by the [URLSearchParams interface](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams). It provides methods
to handle parameter access for both route parameters (`paramMap`) and query parameters (`queryParamMap`).
<table>

View File

@ -178,7 +178,7 @@ For a discussion of the unit testing setup files, [see below](guide/testing#setu
{@a isolated-v-testing-utilities}
### Isolated unit tests vs. the Angular testing utilites
### Isolated unit tests vs. the Angular testing utilities
[Isolated unit tests](guide/testing#isolated-unit-tests "Unit testing without the Angular testing utilities")
examine an instance of a class all by itself without any dependence on Angular or any injected values.

View File

@ -247,12 +247,10 @@ next to the original _ES5_ version for comparison:
</code-pane>
</code-tabs>
{@a name-constructor}
<div class="callout is-helpful">
{@a name-constructor}
### Name the constructor
A **named** constructor displays clearly in the console log
if the component throws a runtime error.
An **unnamed** constructor displays as an anonymous function, for example, `class0`,

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 857 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View File

Before

Width:  |  Height:  |  Size: 257 KiB

After

Width:  |  Height:  |  Size: 257 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -573,5 +573,14 @@
"website": "http://www.methotic.com",
"bio": "Thierry is a senior consultant and trainer, specialized on Angular, and a Google Developer Expert.",
"group": "GDE"
},
"gerardsans": {
"name": "Gerard Sans",
"picture": "gerardsans.jpg",
"twitter": "gerardsans",
"website": "https://medium.com/@gerard.sans",
"bio": "Gerard is very excited about the future of the Web and JavaScript. Always happy Computer Science Engineer and humble Google Developer Expert. He loves to share his learnings by giving talks, trainings and writing about cool technologies. He loves running AngularZone and GraphQL London, mentoring students and giving back to the community.",
"group": "GDE"
}
}

View File

@ -8,7 +8,7 @@
<div class="feature-section">
<div class="feature-header">
<div class="text-headline">Cross Platform</div>
<img src="../assets/images/icons/feature-icon.svg" height="70px">
<img src="generated/images/marketing/features/feature-icon.svg" height="70px">
</div>
<div class="feature-row">
@ -34,7 +34,7 @@
<div class="feature-section">
<div class="feature-header">
<div class="text-headline">Speed and Performance</div>
<img src="../assets/images/icons/feature-icon.svg" height="70px">
<img src="generated/images/marketing/features/feature-icon.svg" height="70px">
</div>
<div class="feature-row">
@ -59,7 +59,7 @@
<div class="feature-section">
<div class="feature-header">
<div class="text-headline">Productivity</div>
<img src="../assets/images/icons/feature-icon.svg" height="70px">
<img src="generated/images/marketing/features/feature-icon.svg" height="70px">
</div>
<div class="feature-row">
@ -84,7 +84,7 @@
<div class="feature-section">
<div class="feature-header">
<div class="text-headline">Full Development Story</div>
<img src="../assets/images/icons/feature-icon.svg" height="70px">
<img src="generated/images/marketing/features/feature-icon.svg" height="70px">
</div>
<div class="feature-row">

View File

@ -1,10 +1,10 @@
<!--FULL HEADER BLOCK-->
<!-- FULL HEADER BLOCK -->
<header>
<!--BACKGROUND IMAGE-->
<!-- BACKGROUND IMAGE -->
<div class="background-sky hero"></div>
<!--INTRO SECTION -->
<!-- INTRO SECTION -->
<section id="intro">
<!-- LOGO -->
@ -12,35 +12,37 @@
<img src="assets/images/logos/angular/angular.svg"/>
</div>
<!-- CONTAINER -->
<!-- CONTAINER -->
<div class="homepage-container">
<!-- container content starts -->
<div class="hero-headline no-toc">One framework.<br>Mobile &amp; desktop.</div>
<a class="button hero-cta" href="guide/quickstart">Get Started</a>
</div><!-- CONTAINER END -->
</section>
</div>
</section>
</header>
<!-- MAIN CONTENT -->
<article>
<h1 class="no-toc" style="display: none"></h1>
<div class="home-rows">
<!--Announcement Bar-->
<!-- Announcement Bar -->
<div class="homepage-container">
<div class="announcement-bar">
<img src="generated/images/marketing/angular-mix.png" height="40" width="151">
<img src="generated/images/marketing/home/angular-mix.png" height="40" width="151">
<p>Join us at our newest event, October 2017</p>
<a class="button" href="https://angularmix.com/">Learn More</a>
</div>
</div>
</div>
<!-- Group 1-->
<!-- Group 1 -->
<div layout="row" layout-xs="column" class="home-row homepage-container">
<div class="promo-img-container promo-1">
<div>
<img height="222" width="340" src="assets/images/home/responsive-framework.svg" alt="responsive framework">
<img height="222" width="340" src="generated/images/marketing/home/responsive-framework.svg" alt="responsive framework">
</div>
</div>
@ -53,7 +55,8 @@
</div>
</div>
<hr>
<!-- Group 2-->
<!-- Group 2 -->
<div layout="row" layout-xs="column" class="home-row">
<div class="text-container">
<div class="text-block">
@ -65,16 +68,16 @@
<div class="promo-img-container promo-2">
<div>
<img height="222" width="323" src="assets/images/home/speed-performance.svg" alt="speed and performance">
<img height="222" width="323" src="generated/images/marketing/home/speed-performance.svg" alt="speed and performance">
</div>
</div>
</div>
<hr>
<!-- Group 3-->
<!-- Group 3 -->
<div layout="row" layout-xs="column" class="home-row">
<div class="promo-img-container promo-3">
<div><img src="assets/images/home/joyful-development.png" alt="IDE example"></div>
<div><img src="generated/images/marketing/home/joyful-development.svg" alt="IDE example"></div>
</div>
<div class="text-container">
@ -88,9 +91,8 @@
</div>
<hr>
<!-- Group 4-->
<!-- Group 4 -->
<div layout="row" layout-xs="column" class="home-row">
<div class="text-container">
<div class="text-block l-pad-top-2">
<div class="text-headline">Loved by Millions</div>
@ -100,25 +102,24 @@
<div class="promo-img-container promo-4">
<div>
<img src="assets/images/home/loved-by-millions.png" alt="angular on the map" width="455" height="228">
<img src="generated/images/marketing/home/loved-by-millions.svg" alt="angular on the map" width="455" height="228">
</div>
</div>
</div>
<!-- CTA CARDS -->
<div layout="row" layout-xs="column" class="home-row">
<a href="guide/quickstart">
<div class="card">
<img src="../assets/images/icons/code-icon.svg" height="70px">
<!-- CTA CARDS -->
<div layout="row" layout-xs="column" class="home-row">
<a href="guide/quickstart">
<div class="card">
<img src="generated/images/marketing/home/code-icon.svg" height="70px">
<div class="card-text-container">
<div class="text-headline">Get Started</div>
<p>Start building your Angular application.</p>
</div>
</div>
</a>
</div>
</div>
</a>
</div>
</div> <!-- end of home rows -->
</div><!-- end of home rows -->
</article>

View File

@ -1,116 +0,0 @@
<header class="hero background-sky">
<h1 class="hero-title no-toc">News</h1>
<div class="clear"></div>
</header>
<artice>
<div class="grid-fluid l-space-bottom-2">
<div class="c12 text-center"><h3 class="text-headline text-uppercase"> Core Team</h3></div>
<div class="clear"></div>
</div>
<div class="grid-fluid">
<div class="c6">
<div class="article-card">
<div class="date">Oct 12, 2016</div>
<div class="title"><a target="_blank"
href="http://angularjs.blogspot.com/2016/10/angular-210-now-available.html">Angular
2.1.0 Now Available</a></div>
<p>Angular version 2.1.0 - incremental-metamorphosis - is a minor release following our
announced adoption of Semantic Versioning...</p>
<div class="author"><img src="generated/images/bios/stephenfluin.jpg">
<div class="posted">Posted by <b>Stephen Fluin</b></div>
</div>
</div>
</div>
<div class="c6">
<div class="article-card">
<div class="date">Oct 7, 2016</div>
<div class="title"><a target="_blank"
href="http://angularjs.blogspot.com/2016/10/versioning-and-releasing-angular.html">Versioning
and Releasing Angular</a></div>
<p>In order for the ecosystem around Angular to thrive, developers need stability from the
Angular framework so that reusable components and libraries, tools and learned practices
dont go obsolete unexpectedly...</p>
<div class="author"><img src="generated/images/bios/igor-minar.jpg">
<div class="posted">Posted by <b>Igor Minar</b></div>
</div>
</div>
</div>
</div>
<div class="grid-fluid l-space-bottom-2 l-space-top-4">
<div class="c12 text-center"><h3 class="text-headline text-uppercase"> Developer Community</h3>
</div>
<div class="clear"></div>
</div>
<div class="grid-fluid">
<div class="c6">
<div class="article-card">
<div class="date">Oct 30, 2016</div>
<div class="title"><a target="_blank"
href="https://www.thepolyglotdeveloper.com/2016/10/use-pre-populated-sqlite-database-nativescript-angular-2/">Use
A Pre-Populated SQLite Database With NativeScript And Angular 2</a></div>
<p>I figured it would be a good idea to demonstrate how to ship a NativeScript Angular 2
application with a pre-filled SQLite database rather than populating it on-the-fly....</p>
<div class="author"><img src="generated/images/bios/shield-bio-placeholder.png">
<div class="posted">Posted by <b>Nic Raboy</b></div>
</div>
</div>
</div>
<div class="c6">
<div class="article-card">
<div class="date">Oct 13, 2016</div>
<div class="title"><a target="_blank"
href="http://blog.thoughtram.io/angular/2016/10/13/two-way-data-binding-in-angular-2.html">Two-way
Data Binding in Angular 2</a></div>
<p>If there was one feature in Angular that made us go “Wow”, then it was probably its
two-way data binding system. Changes in the application state have been automagically
reflected into the view...</p>
<div class="author"><img src="generated/images/bios/angular-gde-bio-placeholder.png">
<div class="posted">Posted by <b>Pascal Precht</b></div>
</div>
</div>
</div>
</div>
<div class="grid-fluid">
<div class="c6">
<div class="article-card">
<div class="date">Oct 10, 2016</div>
<div class="title"><a target="_blank"
href="http://www.creativebloq.com/how-to/build-a-material-design-app-with-angular-2">Build
a Material Design app with Angular 2</a></div>
<p>This walkthrough reveals how to create a DialogComponent and to-do app with Angular
Material and the Angular CLI...</p>
<div class="author"><img src="generated/images/bios/shield-bio-placeholder.png">
<div class="posted">Posted by <b>Daniel Zen</b></div>
</div>
</div>
</div>
<div class="c6">
<div class="article-card">
<div class="date">Sept 30, 2016</div>
<div class="title"><a target="_blank"
href="http://www.simb.co/angular-cli-using-docker/?platform=hootsuite">Using
Angular CLI to create Angular 2 applications in Docker</a></div>
<p>Angular CLI is a great tool for developing Angular 2 applications. I thought it would be
fun to do a quick demo...</p>
<div class="author"><img src="generated/images/bios/shield-bio-placeholder.png">
<div class="posted">Posted by <b>Simeon Bateman</b></div>
</div>
</div>
</div>
</div>
<div class="grid-fluid l-space-bottom-2 l-space-top-4">
<div class="c12 text-center"><h3 class="text-headline text-uppercase">Twitter</h3></div>
<div class="clear"></div>
<div class="grid-fluid">
<div class="c3"><p></p></div>
<div class="c6">
<div class="article-card">
<div class="title"><a href="http://twitter.com/angularjs" data-show-count="false"
class="twitter-follow-button">Follow @angularjs</a></div>
<p><a class="twitter-timeline" data-chrome="nofooter noborders noheader"
href="http://twitter.com/angularjs" data-widget-id="700150278465523713"></a></p>
</div>
</div>
</div>
</div>
</article>

View File

@ -17,7 +17,7 @@
"title": "Events"
},
{
"url": "https://blog.angularjs.org/",
"url": "https://blog.angular.io/",
"title": "Blog"
}
],
@ -39,7 +39,7 @@
"title": "Events"
},
{
"url": "https://blog.angularjs.org/",
"url": "https://blog.angular.io/",
"title": "Blog"
}
]
@ -282,6 +282,11 @@
"title": "Internationalization (i18n)",
"tooltip": "Translate the app's template text into multiple languages."
},
{
"url": "guide/language-service",
"title": "Language Service",
"tooltip": "Use Angular Language Service to speed up dev time."
},
{
"url": "guide/security",
"title": "Security",

View File

@ -137,7 +137,7 @@ Create a file in the `app` folder called `hero.service.ts`.
The naming convention for service files is the service name in lowercase followed by `.service`.
For a multi-word service name, use lower [dash-case](guide/glossary).
For a multi-word service name, use lower [dash-case](guide/glossary#dash-case).
For example, the filename for `SpecialSuperHeroService` is `special-super-hero.service.ts`.
</div>

View File

@ -83,10 +83,6 @@ Added hero "Zero" to confirm that the data service can handle a hero with `id==0
Don't worry about the details of this backend substitution; you can
skip it when you have a real web API server.
Read more about the in-memory web API in the
[Appendix: Tour of Heroes in-memory web api](guide/http#in-mem-web-api)
section of the [HTTP Client](guide/http#in-mem-web-api) page.
</div>
## Heroes and HTTP

View File

@ -10,8 +10,8 @@
},
"static.ignore": [
"\\.js\\.map$",
"^/assets/images/.*/unused/",
"^/generated/(?:docs/(?!api/api-list\\.json).*|images|live-examples|zips)/"
"^(?:/|\\\\)assets(?:/|\\\\)images(?:/|\\\\).*(?:/|\\\\)_unused(?:/|\\\\)",
"^(?:/|\\\\)generated(?:/|\\\\)(?:docs(?:/|\\\\)(?!api(?:/|\\\\)api-list\\.json).*|images(?:/|\\\\)(?!marketing(?:/|\\\\)).*|live-examples|zips)(?:/|\\\\)"
],
"static.versioned": [
"\\.[0-9a-z]{20}\\."

View File

@ -33,8 +33,9 @@
"docs-test": "node tools/transforms/test.js",
"serve-and-sync": "concurrently --kill-others \"yarn docs-watch\" \"yarn start\"",
"~~update-webdriver": "webdriver-manager update --standalone false --gecko false",
"boilerplate:add": "node ./tools/examples/add-example-boilerplate add",
"boilerplate:remove": "node ./tools/examples/add-example-boilerplate remove",
"boilerplate:add": "node ./tools/examples/example-boilerplate add",
"boilerplate:remove": "node ./tools/examples/example-boilerplate remove",
"boilerplate:test": "node tools/examples/test.js",
"generate-plunkers": "node ./tools/plunker-builder/generatePlunkers",
"generate-zips": "node ./tools/example-zipper/generateZips",
"sw-manifest": "ngu-sw-manifest --dist dist --in ngsw-manifest.json --out dist/ngsw-manifest.json",
@ -48,17 +49,18 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^4.2.4",
"@angular/common": "^4.2.4",
"@angular/compiler": "^4.2.4",
"@angular/core": "^4.2.4",
"@angular/forms": "^4.2.4",
"@angular/http": "^4.2.4",
"@angular/material": "^2.0.0-beta.7",
"@angular/platform-browser": "^4.2.4",
"@angular/platform-browser-dynamic": "^4.2.4",
"@angular/platform-server": "^4.2.4",
"@angular/router": "^4.2.4",
"@angular/animations": "^4.3.1",
"@angular/cdk": "^2.0.0-beta.8",
"@angular/common": "^4.3.1",
"@angular/compiler": "^4.3.1",
"@angular/core": "^4.3.1",
"@angular/forms": "^4.3.1",
"@angular/http": "^4.3.1",
"@angular/material": "^2.0.0-beta.8",
"@angular/platform-browser": "^4.3.1",
"@angular/platform-browser-dynamic": "^4.3.1",
"@angular/platform-server": "^4.3.1",
"@angular/router": "^4.3.1",
"@angular/service-worker": "^1.0.0-beta.16",
"classlist.js": "^1.1.20150312",
"core-js": "^2.4.1",
@ -72,7 +74,7 @@
},
"devDependencies": {
"@angular/cli": "angular/cli-builds#webpack-next",
"@angular/compiler-cli": "^4.2.4",
"@angular/compiler-cli": "^4.3.1",
"@types/jasmine": "^2.5.52",
"@types/node": "~6.0.60",
"archiver": "^1.3.0",
@ -81,7 +83,7 @@
"concurrently": "^3.4.0",
"cross-spawn": "^5.1.0",
"dgeni": "^0.4.7",
"dgeni-packages": "^0.20.0-rc.5",
"dgeni-packages": "^0.20.0",
"entities": "^1.1.1",
"eslint": "^3.19.0",
"eslint-plugin-jasmine": "^2.2.0",

View File

@ -4,12 +4,8 @@ set -eu -o pipefail
readonly thisDir=$(cd $(dirname $0); pwd)
readonly parentDir=$(dirname $thisDir)
readonly TOKEN=${ANGULAR_PAYLOAD_FIREBASE_TOKEN:-}
readonly PROJECT_NAME="angular-payload-size"
# temporarily turn on debugging - we disable it later in the script to prevent token leak
set -x
source ${thisDir}/_payload-limits.sh
failed=false
@ -45,15 +41,21 @@ timestamp=$(date +%s)
payloadData="$payloadData\"timestamp\": $timestamp, "
# Add change source: application, dependencies, or 'application+dependencies'
applicationChanges=$(git diff --name-only $TRAVIS_COMMIT_RANGE $parentDir | grep -v ${parentDir}/content | grep -v ${parentDir}/yarn.lock | wc -l)
dependencyChanges=$(git diff --name-only $TRAVIS_COMMIT_RANGE ${parentDir}/yarn.lock | wc -l)
applicationChanged=false
dependenciesChanged=false
if [[ $(git diff --name-only $TRAVIS_COMMIT_RANGE $parentDir | grep -v aio/yarn.lock | grep -v content) ]]; then
applicationChanged=true
fi
if [[ $(git diff --name-only $TRAVIS_COMMIT_RANGE $parentDir/yarn.lock) ]]; then
dependenciesChanged=true
fi
if [[ $dependencyChanges -eq 1 ]] && [[ $applicationChanges -eq 0 ]]; then
if $dependenciesChanged && $applicationChanged; then
change='application+dependencies'
elif $dependenciesChanged; then
# only yarn.lock changed
change='dependencies'
elif [[ $dependencyChanges -eq 1 ]] && [[ $applicationChanges -gt 0 ]]; then
change='application+dependencies'
elif [[ $applicationChanges -gt 0 ]]; then
elif $applicationChanged; then
change='application'
else
# Nothing changed in aio/
@ -71,7 +73,7 @@ if [[ "$TRAVIS_PULL_REQUEST" == "false" ]]; then
# WARNING: FIREBASE_TOKEN should NOT be printed.
set +x
firebase database:update --data "$payloadData" --project $PROJECT_NAME --confirm --token "$TOKEN" $dbPath
firebase database:update --data "$payloadData" --project $PROJECT_NAME --confirm --token "$ANGULAR_PAYLOAD_FIREBASE_TOKEN" $dbPath
fi
if [[ $failed = true ]]; then

View File

@ -19,11 +19,6 @@ const config = require('lighthouse/lighthouse-core/config/default.js');
// Constants
const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/';
// Specify the path to Chrome on Travis
if (process.env.TRAVIS) {
process.env.LIGHTHOUSE_CHROMIUM_PATH = process.env.CHROME_BIN;
}
// Run
_main(process.argv.slice(2));

View File

@ -632,7 +632,6 @@ describe('AppComponent', () => {
it('should initialize the search worker', inject([SearchService], (searchService: SearchService) => {
fixture.detectChanges(); // triggers ngOnInit
expect(searchService.initWorker).toHaveBeenCalled();
expect(searchService.loadIndex).toHaveBeenCalled();
}));
});

View File

@ -48,7 +48,7 @@ export class AppComponent implements OnInit {
* the styling of individual pages.
* You will get three classes:
*
* * `page-...`: computed from the current document id (e.g. news, guide-security, tutorial-toh-pt2)
* * `page-...`: computed from the current document id (e.g. events, guide-security, tutorial-toh-pt2)
* * `folder-...`: computed from the top level folder for an id (e.g. guide, tutorial, etc)
* * `view-...`: computef from the navigation view (e.g. SideNav, TopBar, etc)
*/
@ -76,8 +76,8 @@ export class AppComponent implements OnInit {
get homeImageUrl() {
return this.isSideBySide ?
'assets/images/logos/standard/logo-nav@2x.png' :
'assets/images/logos/standard/shield-large.svg';
'assets/images/logos/angular/logo-nav@2x.png' :
'assets/images/logos/angular/shield-large.svg';
}
get isOpened() { return this.isSideBySide && this.isSideNavDoc; }
get mode() { return this.isSideBySide ? 'side' : 'over'; }
@ -111,8 +111,8 @@ export class AppComponent implements OnInit {
ngOnInit() {
// Do not initialize the search on browsers that lack web worker support
if ('Worker' in window) {
this.searchService.initWorker('app/search/search-worker.js');
this.searchService.loadIndex();
// Delay initialization by up to 2 seconds
this.searchService.initWorker('app/search/search-worker.js', 2000);
}
this.onResize(window.innerWidth);

View File

@ -65,6 +65,13 @@ describe('CodeExampleComponent', () => {
expect(actual).toBe('Great Example');
});
it('should remove the `title` attribute after initialisation', () => {
TestBed.overrideComponent(HostComponent, {
set: {template: '<code-example title="Great Example"></code-example>'}});
createComponent(oneLineCode);
expect(codeExampleDe.nativeElement.getAttribute('title')).toEqual(null);
});
it('should pass hideCopy to CodeComonent', () => {
TestBed.overrideComponent(HostComponent, {
set: {template: '<code-example hideCopy="true"></code-example>'}});

View File

@ -45,6 +45,8 @@ export class CodeExampleComponent implements OnInit {
this.path = element.getAttribute('path') || '';
this.region = element.getAttribute('region') || '';
this.title = element.getAttribute('title') || '';
// Now remove the title attribute to prevent unwanted tooltip popups when hovering over the code.
element.removeAttribute('title');
this.isAvoid = this.path.indexOf('.avoid.') !== -1;
this.hideCopy = this.isAvoid || getBoolFromAttribute(element, ['hidecopy', 'hide-copy']);

View File

@ -1,5 +1,5 @@
import { Component } from '@angular/core';
import { async, ComponentFixture, TestBed, inject } from '@angular/core/testing';
import { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { SearchBoxComponent } from './search-box.component';
import { MockSearchService } from 'testing/search.service';
@ -36,30 +36,67 @@ describe('SearchBoxComponent', () => {
});
describe('initialisation', () => {
it('should get the current search query from the location service', inject([LocationService], (location: MockLocationService) => {
it('should get the current search query from the location service',
inject([LocationService], (location: MockLocationService) => fakeAsync(() => {
location.search.and.returnValue({ search: 'initial search' });
component.ngOnInit();
expect(location.search).toHaveBeenCalled();
tick(300);
expect(host.searchHandler).toHaveBeenCalledWith('initial search');
expect(component.searchBox.nativeElement.value).toEqual('initial search');
})));
});
describe('onSearch', () => {
it('should debounce by 300ms', fakeAsync(() => {
component.doSearch();
expect(host.searchHandler).not.toHaveBeenCalled();
tick(300);
expect(host.searchHandler).toHaveBeenCalled();
}));
it('should pass through the value of the input box', fakeAsync(() => {
const input = fixture.debugElement.query(By.css('input'));
input.nativeElement.value = 'some query (input)';
component.doSearch();
tick(300);
expect(host.searchHandler).toHaveBeenCalledWith('some query (input)');
}));
it('should only send events if the search value has changed', fakeAsync(() => {
const input = fixture.debugElement.query(By.css('input'));
input.nativeElement.value = 'some query';
component.doSearch();
tick(300);
expect(host.searchHandler).toHaveBeenCalledTimes(1);
component.doSearch();
tick(300);
expect(host.searchHandler).toHaveBeenCalledTimes(1);
input.nativeElement.value = 'some other query';
component.doSearch();
tick(300);
expect(host.searchHandler).toHaveBeenCalledTimes(2);
}));
});
describe('on input', () => {
it('should trigger the onSearch event', () => {
it('should trigger a search', () => {
const input = fixture.debugElement.query(By.css('input'));
input.nativeElement.value = 'some query (input)';
spyOn(component, 'doSearch');
input.triggerEventHandler('input', { });
expect(host.searchHandler).toHaveBeenCalledWith('some query (input)');
expect(component.doSearch).toHaveBeenCalled();
});
});
describe('on keyup', () => {
it('should trigger the onSearch event', () => {
it('should trigger a search', () => {
const input = fixture.debugElement.query(By.css('input'));
input.nativeElement.value = 'some query (keyup)';
spyOn(component, 'doSearch');
input.triggerEventHandler('keyup', { });
expect(host.searchHandler).toHaveBeenCalledWith('some query (keyup)');
expect(component.doSearch).toHaveBeenCalled();
});
});
@ -73,28 +110,11 @@ describe('SearchBoxComponent', () => {
});
describe('on click', () => {
it('should trigger the search event', () => {
it('should trigger a search', () => {
const input = fixture.debugElement.query(By.css('input'));
input.nativeElement.value = 'some query (click)';
spyOn(component, 'doSearch');
input.triggerEventHandler('click', { });
expect(host.searchHandler).toHaveBeenCalledWith('some query (click)');
});
});
describe('event filtering', () => {
it('should only send events if the search value has changed', () => {
const input = fixture.debugElement.query(By.css('input'));
input.nativeElement.value = 'some query';
input.triggerEventHandler('input', { });
expect(host.searchHandler).toHaveBeenCalledTimes(1);
input.triggerEventHandler('input', { });
expect(host.searchHandler).toHaveBeenCalledTimes(1);
input.nativeElement.value = 'some other query';
input.triggerEventHandler('input', { });
expect(host.searchHandler).toHaveBeenCalledTimes(2);
expect(component.doSearch).toHaveBeenCalled();
});
});

View File

@ -26,10 +26,11 @@ import 'rxjs/add/operator/distinctUntilChanged';
})
export class SearchBoxComponent implements OnInit {
private searchDebounce = 300;
private searchSubject = new Subject<string>();
@ViewChild('searchBox') searchBox: ElementRef;
@Output() onSearch = this.searchSubject.distinctUntilChanged();
@Output() onSearch = this.searchSubject.distinctUntilChanged().debounceTime(this.searchDebounce);
@Output() onFocus = new EventEmitter<string>();
constructor(private locationService: LocationService) { }

View File

@ -1,24 +1,62 @@
import { ReflectiveInjector, NgZone } from '@angular/core';
import { fakeAsync, tick } from '@angular/core/testing';
import { Observable } from 'rxjs/Observable';
import { SearchService } from './search.service';
import { WebWorkerClient } from 'app/shared/web-worker';
describe('SearchService', () => {
let injector: ReflectiveInjector;
let service: SearchService;
let sendMessageSpy: jasmine.Spy;
let mockWorker: WebWorkerClient;
beforeEach(() => {
sendMessageSpy = jasmine.createSpy('sendMessage').and.returnValue(Observable.of({}));
mockWorker = { sendMessage: sendMessageSpy } as any;
spyOn(WebWorkerClient, 'create').and.returnValue(mockWorker);
injector = ReflectiveInjector.resolveAndCreate([
SearchService,
{ provide: NgZone, useFactory: () => new NgZone({ enableLongStackTrace: false }) }
]);
service = injector.get(SearchService);
});
describe('loadIndex', () => {
it('should send a "load-index" message to the worker');
it('should connect the `ready` property to the response to the "load-index" message');
describe('initWorker', () => {
it('should create the worker and load the index after the specified delay', fakeAsync(() => {
service.initWorker('some/url', 100);
expect(WebWorkerClient.create).not.toHaveBeenCalled();
expect(mockWorker.sendMessage).not.toHaveBeenCalled();
tick(100);
expect(WebWorkerClient.create).toHaveBeenCalledWith('some/url', jasmine.any(NgZone));
expect(mockWorker.sendMessage).toHaveBeenCalledWith('load-index');
}));
});
describe('search', () => {
it('should send a "query-index" message to the worker');
it('should push the response to the `searchResults` observable');
beforeEach(() => {
// We must initialize the service before calling search
service.initWorker('some/url', 100);
});
it('should trigger a `loadIndex` synchronously', () => {
service.search('some query');
expect(mockWorker.sendMessage).toHaveBeenCalledWith('load-index');
});
it('should send a "query-index" message to the worker', () => {
service.search('some query');
expect(mockWorker.sendMessage).toHaveBeenCalledWith('query-index', 'some query');
});
it('should push the response to the `searchResults` observable', () => {
const mockSearchResults = { results: ['a', 'b'] };
(mockWorker.sendMessage as jasmine.Spy).and.returnValue(Observable.of(mockSearchResults));
let searchResults: any;
service.searchResults.subscribe(results => searchResults = results);
service.search('some query');
expect(searchResults).toEqual(mockSearchResults);
});
});
});

View File

@ -7,8 +7,10 @@ can be found in the LICENSE file at http://angular.io/license
import { NgZone, Injectable, Type } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import 'rxjs/add/operator/publishLast';
import 'rxjs/add/observable/race';
import 'rxjs/add/observable/timer';
import 'rxjs/add/operator/concatMap';
import 'rxjs/add/operator/publish';
import { WebWorkerClient } from 'app/shared/web-worker';
export interface SearchResults {
@ -27,26 +29,50 @@ export interface SearchResult {
@Injectable()
export class SearchService {
private worker: WebWorkerClient;
private ready: Observable<boolean>;
private resultsSubject = new ReplaySubject<SearchResults>(1);
readonly searchResults = this.resultsSubject.asObservable();
private searchesSubject = new ReplaySubject<string>(1);
searchResults: Observable<SearchResults>;
constructor(private zone: NgZone) {}
initWorker(workerUrl) {
this.worker = new WebWorkerClient(new Worker(workerUrl), this.zone);
}
loadIndex() {
const ready = this.ready = this.worker.sendMessage<boolean>('load-index').publishLast();
// trigger the index to be loaded immediately
ready.connect();
/**
* Initialize the search engine. We offer an `initDelay` to prevent the search initialisation from delaying the
* initial rendering of the web page. Triggering a search will override this delay and cause the index to be
* loaded immediately.
*
* @param workerUrl the url of the WebWorker script that runs the searches
* @param initDelay the number of milliseconds to wait before we load the WebWorker and generate the search index
*/
initWorker(workerUrl: string, initDelay: number) {
const searchResults = Observable
// Wait for the initDelay or the first search
.race(
Observable.timer(initDelay),
this.searchesSubject.first()
)
.concatMap(() => {
// Create the worker and load the index
const worker = WebWorkerClient.create(workerUrl, this.zone);
return worker.sendMessage('load-index').concatMap(() =>
// Once the index has loaded, switch to listening to the searches coming in
this.searchesSubject.switchMap((query) =>
// Each search gets switched to a web worker message, whose results are returned via an observable
worker.sendMessage<SearchResults>('query-index', query)
)
);
}).publish();
// Connect to the observable to kick off the timer
searchResults.connect();
// Expose the connected observable to the rest of the world
this.searchResults = searchResults;
}
/**
* Send a search query to the index.
* The results will appear on the `searchResults` observable.
*/
search(query: string) {
this.ready.concatMap(ready => {
return this.worker.sendMessage('query-index', query) as Observable<SearchResults>;
}).subscribe(results => this.resultsSubject.next(results));
this.searchesSubject.next(query);
}
}

View File

@ -16,7 +16,11 @@ export interface WebWorkerMessage {
export class WebWorkerClient {
private nextId = 0;
constructor(private worker: Worker, private zone: NgZone) {
static create(workerUrl: string, zone: NgZone) {
return new WebWorkerClient(new Worker(workerUrl), zone);
}
private constructor(private worker: Worker, private zone: NgZone) {
}
sendMessage<T>(type: string, payload?: any): Observable<T> {

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