Compare commits

..

353 Commits
8.1.3 ... 8.0.3

Author SHA1 Message Date
9b812dc729 release: cut the v8.0.3 release 2019-06-26 13:41:07 -07:00
2eee8d59fe ci: target default pool for linux RBE executions (#31297)
PR Close #31297
2019-06-26 13:31:37 -07:00
f0dc8cfc05 docs: add "ivy" to known scopes in contributing guide (#31293)
Currently the contributing guide misses the ivy scope. This
commit adds ivy to the contributing guide as it is useful
for new contributors to know which scopes are supported.

Note: this is the patch version of #31291

PR Close #31293
2019-06-26 13:31:17 -07:00
79471f7610 docs: correct indention for code example in deployment guide (#31255)
PR Close #31255
2019-06-25 14:44:34 -07:00
54f68c342b docs(core): update code sample for "outputs" attribute (#31199)
The current code sample for (directive) "outputs" attribute is incorrect as it does not provide the usage of "outputs" attribute rather it provides the usage of "exportAs" attribute. This commit update the code sample by correcting the code sample with correct usage of "outputs" attribute.

Fixes https://github.com/angular/angular/issues/29523
Related work https://github.com/angular/angular/pull/30014

This commit continues from the unfinished (https://github.com/angular/angular/pull/30014#issuecomment-485419124, https://github.com/angular/angular/issues/29523#issuecomment-497333146) work.

PR Close #31199
2019-06-25 14:44:09 -07:00
86bfb0172b docs: change note about cli (#31216)
PR Close #31216
2019-06-25 11:58:07 -07:00
52186165ee docs: add note about cli commands (#31216)
PR Close #31216
2019-06-25 11:58:07 -07:00
e9ae885982 ci: add owners for zone.js to CODEOWNERS (#31203)
Follow-up to #30962.

PR Close #31203
2019-06-25 11:20:01 -07:00
8a1bd2c401 docs: fix formatting (#31120)
PR Close #31120
2019-06-25 10:28:51 -07:00
018b695ef2 docs: fix testing example (#31120)
PR Close #31120
2019-06-25 10:28:51 -07:00
1d193df360 ci: enable remote build caching for CI jobs (#31204)
Enables remote caching for CI jobs.

This configuration:

always reads from build cache on CI
only write to build cache for local builds for non-PR CI run

PR Close #31204
2019-06-25 10:26:44 -07:00
0a46b2acfb fix(docs-infra): separate vendor-specific CSS selectors (#31252)
In #31118, some vendor-specific selectors were combined in one rule-set.
As pointed out in [this comment][1], this would result in the whole
rule-set being ignored by all browsers, since one invalid/unrecognized
selector invalidates the declaration block.

This commit fixes it by defining a separate rule-set per selector. The
list of vendor-specific selectors is also adjusted to better target the
currently supported browsers.

[1]: https://github.com/angular/angular/pull/31118/files#r296923652

PR Close #31252
2019-06-25 10:25:32 -07:00
b63aa4e7ef style(docs-infra): clean up some styles (#31252)
PR Close #31252
2019-06-25 10:25:32 -07:00
6aae19633b build: use checked-in configuration from bazel-toolchains (#31251)
No longer uses docker in order to pull down the toolchain configs
for remote build execution. We don't need to make docker a prerequisite
for working on the Angular repository since we can leverage the checked-in
toolchain configurations from the `@bazel-toolchains` repository.

PR Close #31251
2019-06-25 10:24:44 -07:00
00242e8d6d docs(core): change from CSS Event to DOM event (#31229)
PR Close #31229
2019-06-25 10:22:35 -07:00
4ea231fdbe fix(docs-infra): return full width highlight to sidenav (#31246)
PR Close #31246
2019-06-24 20:17:27 -07:00
6bad2ca586 fix(bazel): exclude all angular schematics folders from metadata build (#31237)
Fixes #31235

PR Close #31237
2019-06-24 18:48:45 -07:00
dabf1325ed ci: upgrade clang-format to 1.0.27 to match master (#31247)
PR Close #31247
2019-06-24 16:50:06 -07:00
987b18596b ci(docs-infra): re-enable payload size checking for test_aio_local and test_aio_local_ivy (#31243)
Previously, payload size checking for `test_aio_local` and
`test_aio_local_ivy` was disabled on the 8.0.x branch (in #31064),
because the numbers (which were cherry-picked from master) did not match
the actual sizes.

This commit updates the numbers for the 8.0.x branch and re-enables the
checks.

PR Close #31243
2019-06-24 15:00:00 -07:00
f470e69fba fix(service-worker): registration failed on Safari (#31140)
Since Angular v8, and commit b3dda0e, `parseUrl()` can be called without
`relativeTo`, thus `new URL()` can be called with `relativeTo = undefined`.

Safari does not like it and the service worker registration fails:
```js
new URL('https://angular.io/') // OK
new URL('https://angular.io/', undefined) // TypeError
```

Closes #31061

PR Close #31140
2019-06-24 14:58:59 -07:00
980bcaf176 fix(bazel): remove unsupported Css pre-processors from ng new (#31234)
Under Bazel, we don't yet support Stylus and Less, and thus we should not offer the users to generate applications which are known not to work.

Closes #31209

PR Close #31234
2019-06-24 14:57:07 -07:00
48f7f65bf4 fix(bazel): update ng new schema to match the current ng new schema of @schematics/angular (#31234)
The schema used in ng-new bazel, includes several outdated options. With this update we match the current version of @schematics/angular: https://github.com/angular/angular-cli/blob/master/packages/schematics/angular/ng-new/schema.json

Relates to #31233

PR Close #31234
2019-06-24 14:57:07 -07:00
7fe95b1882 ci: send failure notifications from saucelabs_tests to dev-infra-ci-failures (#31202)
PR Close #31202
2019-06-21 15:29:36 -07:00
266871baf4 ci: make logic for failure notifications more re-usable (#31202)
PR Close #31202
2019-06-21 15:29:36 -07:00
bc54ecf66e ci: send aio_monitoring failure notifications to the dev-infra-ci-failures channel (#31202)
PR Close #31202
2019-06-21 15:29:36 -07:00
274833ee94 ci: add josephperrott to dev-infra owners (#31205)
PR Close #31205
2019-06-21 15:29:10 -07:00
ff5934597a build: Set up Build Event Service Configuration for RBE executed bazel (#31197)
The Build Event Service (https://docs.bazel.build/versions/master/build-event-protocol.html#the-build-event-service),
allows for build events from bazel builds to be transmitted as opaque bytes to be processed.

Our usage is to send our build events to a Build Event Service an Angular team owned Google Cloud Project which collects
build results and makes each invocation available via a provided URL to view.  The information uploaded includes information
about the build environment, configuration, build status/events, build options, results and actions.

Build Event Protocol Proto: https://github.com/bazelbuild/bazel/blob/0.27.0/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto

PR Close #31197
2019-06-21 15:28:51 -07:00
09b60ed36a feat(docs-infra): change typography font sizes to be rem based (#31118)
PR Close #31118
2019-06-21 14:22:21 -07:00
0bb83b2ba6 docs: update node minimum version (#31192)
Docs for for Travis CI setup suggest using node version 8 when the minimum should be 10. This commit updates the documentation by specifying the minimum required version as 10.

Fixes https://github.com/angular/angular/issues/31185

PR Close #31192
2019-06-21 12:02:39 -07:00
de04741863 docs: clarify wording in Template Syntax (#31119)
PR Close #31119
2019-06-21 10:23:38 -07:00
8ea91887ca docs: mark interfaces as public (#30955)
PR Close #30955
2019-06-21 10:21:13 -07:00
ff184b56eb docs: fix javascript module link (#31181)
PR Close #31181
2019-06-21 10:14:40 -07:00
15d138fdd3 docs: fix typo in browser-support.md (ES1015 --> ES2015) (#31157)
PR Close #31157
2019-06-21 10:14:24 -07:00
1699b54860 docs: add Mosaic library to resources (#31026)
PR Close #31026
2019-06-21 10:14:04 -07:00
07f6b2c018 build: user bazelrc should be able to overwrite all flags (#31164)
After eb00a37eb8 we accidentally regressed due to some
recent changes where more flags were added at the end of the bazelrc. This means that all
flags which were added after the `try-import` can no longer be overwritten easily in the
user project bazelrc file. Technically developers can always overwrite flags though the
command line, but it's a productivity blocker if developers can't permanently overwrite these
flags  through the user config

PR Close #31164
2019-06-20 11:18:13 -07:00
4a193580fe build(docs-infra): upgrade @angular/cli to 8.1.0-beta.2 (#31137)
PR Close #31137
2019-06-20 11:16:36 -07:00
9c222350f9 ci: re-enable payload size tracking (#31138)
Payload size tracking was temporarily disabled in #31057, due to
`CIRCLE_COMPARE_URL` stopping being available. It turned out this was
related to turning on the new [Pipelines][1] feature, which was required
for testing Windows on CircleCI.

Since then, we have turned `Pipelines` off and got `CIRCLE_COMPARE_URL`
back (e.g. see [build 362971][2]). According to CircleCI, failing to
populate `CIRCLE_COMPARE_URL` with `Pipelines` on is a bug and they are
working on fixing it.

[1]: https://circleci.com/docs/2.0/build-processing/
[2]: https://circleci.com/gh/angular/angular/362971

Fixes #31121

PR Close #31138
2019-06-19 15:55:10 -07:00
c36edffe2a docs: fix bad tag (#31115)
PR Close #31115
2019-06-19 15:52:48 -07:00
13b984d72b docs: fix bad anchors (#31115)
PR Close #31115
2019-06-19 15:52:48 -07:00
f00eff5916 docs: fix code example formats (#31115)
PR Close #31115
2019-06-19 15:52:48 -07:00
31ee45efdc docs: add instructions for es5 serve and test targets (#31115)
PR Close #31115
2019-06-19 15:52:47 -07:00
b68f2d6fa5 docs: remove inappropriate link (#31091)
PR Close #31091
2019-06-19 15:31:57 -07:00
d8def6d728 refactor(docs-infra): move auto-link filters to dedicated directory (#31051)
These filters have generic names (e.g. `filterPipes`), which do not make
their purpose obvious. Moving them to a dedicated `auto-link-filters`
directory should help with that.

PR Close #31051
2019-06-19 14:59:35 -07:00
e8f464409c fix(docs-infra): do not auto-link http:// to the common/http (#31051)
Previously, our auto-linking feature would match `http` in URLs (such as
`http://...`) to the `common/http` package and automatically create a
link to that, which was undesirable. While it is possible to work around
that via `<code class="no-auto-link">http://...</code>`, most people
didn't even realize the issue.

Since in this case it is possible to reliably know it is a false match,
this commit fixes it by applying a custom auto-link filter that ignores
all docs for `http`, if it comes before `://`.

Fixes #31012

PR Close #31051
2019-06-19 14:59:35 -07:00
a73b8a62c8 release: cut the v8.0.2 release 2019-06-19 10:33:28 -07:00
2fe8f2b1e0 build: update buildifier to version that supports windows (#31129)
* Updates buildifier to a version that also comes with windows binaries.
* Fixes a few new formatting/lint warnings
* Removes the `args-order` warning because it is no longer a warning.. and is now part of the formatter.

Patch version of #31112

PR Close #31129
2019-06-19 08:50:43 -07:00
f1c08c6918 docs: add core and cli version alignment note (#30976)
docs: add core and cli version alignment note
PR Close #30976
2019-06-19 08:49:25 -07:00
bf9de8ca53 test: update side-effects test to be more descriptive (#31005)
This test will now list diffs for failed expectations and the full command to update them.

Fix #30570

PR Close #31005
2019-06-18 13:58:59 -07:00
df37c47ac5 ci: add jasonaden to forms owners (#31117)
PR Close #31117
2019-06-18 13:58:30 -07:00
788d19c036 build: enable shard_count for some jasmine tests that have many specs (#31009)
This partitions the spects across multiple processes so they run in parallel.

PR Close #31009
2019-06-18 12:11:31 -07:00
8492499fe7 docs: add missing word in build and deploy guide to clarify sentence (#31093)
PR Close #31093
2019-06-18 11:00:28 -07:00
48174010a1 docs: update group() link to point to the animations group API (#30618)
PR Close #30618
2019-06-18 10:49:46 -07:00
1460e46ba1 build: ts-api-guardian npm package contains invalid references (#31096)
Currently when building the `ts-api-guardian` npm package,
the labels are not properly replaced after recent changes to
the `entry_point` attribute. This means that the `ts-api-guardian`
package is currently not usable externally.

PR Close #31096
2019-06-18 09:50:42 -07:00
a7ff7d8d27 docs: refresh TypeScript configuration guide with updated info and files (#31097)
This removes the hard-coded tsconfig.json to use a separate file.
The tsconfig.0.json is added to the getting-started example folder
because have to check it with every major release
Also updates the text regarding defaults for TypeScript compilation targets
and typings

PR Close #31097
2019-06-18 09:47:49 -07:00
eb970b4626 docs: rewrite Observable examples with pipable operators (#31074)
PR Close #31074
2019-06-18 09:47:07 -07:00
18d301258a docs: change interceptor documentation (#30969)
PR Close #30969
2019-06-18 09:46:35 -07:00
6a01fa532c docs: add mock heroes to the code review tabs for TOH pt. 2 (#31080)
PR Close #31080
2019-06-17 16:34:39 -07:00
e190a7e9de fix(docs-infra): fix search result header color (#30924)
PR Close #30924
2019-06-17 16:33:54 -07:00
53c6425954 ci: publish snapshots job is unable to decode github token (#31099)
The publish_snapshots job is currently not able to decode the Github
token because the openssl version changed. This is because the default
digest for more recent openssl version has been updated and the github
token file has been encrypted with an old digest. We need to ensure
that the md5 digest is used for decryption as that matches the
digest used for encryption.

PR Close #31099
2019-06-17 13:56:13 -07:00
c198dc6c19 fix(bazel): builder workspace should use nodejs v10.16.0 (#31088)
The generated Bazel workspace by the `@angular/bazel` builder should
use the latest stable NodeJS version. This is necessary because some
packages like `selenium-webdriver` which are part of the default bazel
setup in order to support `ng e2e` depend on a minimum NodeJS version
of `10.15.0`.. This means that running e2e tests in a plain new bazel CLI
project (`ng new {projectName} --collection=@angular/bazel`) errors.

```
command.
 (error selenium-webdriver@4.0.0-alpha.3: The engine "node" is incompatible with
 this module. Expected version ">= 10.15.0". Got "10.13.0"
error Found incompatible module
)
```

PR Close #31088
2019-06-17 13:07:28 -07:00
d1b26dd3a1 ci: update nodejs version to v10.16.0 (#31088)
Updates the NodeJS version to the latest stable version at the time of
writing (v10.16.0). We need to update our image to use a minimum NodeJS
version of v10.15.0 because new CLI apps automatically install a non-locked
version of selenium-webdriver that now requires NodeJS >= 10.15.0 since the
latest release of 17th June 2019 (4.0.0-alpha.3).

See CI failures: https://circleci.com/gh/angular/angular/359077

PR Close #31088
2019-06-17 13:07:28 -07:00
ce7131f3fb ci(docs-infra): disable payload size tracking for test_aio_local and test_aio_local_ivy (#31064)
Payload size tracking for AIO introduced in the previous commit (c596795e64) works fine for master branch, but fails in patch branch. In order to keep CI for patch branch healthy, the size tracking is temporary disabled and will be turned on again after additional investigation.

PR Close #31064
2019-06-14 16:03:39 -07:00
934702892e ci(docs-infra): check and track payload sizes for test_aio_local and test_aio_local_ivy (#31047)
PR Close #31047
2019-06-14 14:38:11 -07:00
8a830a72e2 ci(docs-infra): run PWA score tests after unit/e2e tests (#31047)
Previously, we run the PWA score tests before unit/e2e tests, because
the latter would destroy the `dist/` directory required by the former.

Since cli@6, unit/e2e tests no longer detroy the `dist/` directory, so
it is now safe to run the unit/e2e tests first. This is preferrable,
since they are conceptually lower-level and any error messages (in case
of breakage) are more specific/actionable.

Related discussion about cli behavior:
- angular/angular-cli#4366
- angular/angular-cli#14701

PR Close #31047
2019-06-14 14:38:11 -07:00
2abb54c4a1 docs: rewrite attribute binding section and add example (#26004)
PR Close #26004
2019-06-14 12:21:28 -07:00
44632bb700 docs: edit codeowners for new Template Syntax examples (#31060)
PR Close #31060
2019-06-14 11:54:30 -07:00
e33b382ab4 docs: edit and add example for Template Expression Operators section of Template Syntax (#28087)
PR Close #28087
2019-06-14 11:53:51 -07:00
c4da400db4 docs: rewrite inputs/outputs section of Template Syntax (#27685)
PR Close #27685
2019-06-14 11:53:14 -07:00
c40e6b2edc docs: edit template ref vars copy and example (#27371)
PR Close #27371
2019-06-14 11:52:34 -07:00
978fc27314 docs: rewrite built-in directives section (#27273)
PR Close #27273
2019-06-14 11:51:47 -07:00
b9f2bbb7d1 docs: add example and edit two-way-binding section of Template Syntax (#26278)
PR Close #26278
2019-06-14 11:50:04 -07:00
9654d646ae docs: rewrite property binding section and add example (#25770)
PR Close #25770
2019-06-14 11:47:35 -07:00
7f214499e8 fix(language-service): Remove 'any' in getQuickInfoAtPosition (#31014)
PR Close #31014
2019-06-14 10:46:17 -07:00
a3d55a9d27 build(docs-infra): update browserlist configuration file (#31045)
More specifically:
- Remove Chrome 41, which was needed for googlebot support but not any
  more.
- Remove IE 9-10, because we don't expect developers to be using them.
- Expand support from _last 2 versions_ to _last 2 **major** versions_.

PR Close #31045
2019-06-14 10:43:22 -07:00
e222b8761e docs: minor fix in get-commit-range.js docs (#31049)
PR Close #31049
2019-06-14 10:41:43 -07:00
1435c0b3a9 docs(aio): add missing description to dev.to link (#30960)
PR Close #30960
2019-06-14 10:41:13 -07:00
0a7aebbcf5 fix(core): temporarily remove @deprecated jsdoc tag for a TextBedStatic.get overload (#30714)
Followup to #30514 which did the same for `TestBed`, but `TestBedStatic` was necessary too.

PR Close #30714
2019-06-14 10:40:43 -07:00
bd7f91feac docs: rewrite binding-syntax section in template-syntax.md (#25561)
PR Close #25561
2019-06-14 10:25:07 -07:00
3bbc89b958 ci: temporarily disable payload size tracking (#31057)
The `CIRCLE_COMPARE_URL` is not available in builds any more since we
enabled `Pipelines` on CircleCI. We have contected CircleCI, but until
this is solved we cannot get the commit range and thus disabling
uploading of payload size data to avoid broken builds.

PR Close #31057
2019-06-14 09:19:18 -07:00
52d98e563d docs: fix broken link in singleton services doc (#31007)
PR Close #31007
2019-06-13 17:05:21 -07:00
b279f8bd62 docs: add no-auto-link instructions to docs style guide (#30980)
PR Close #30980
2019-06-13 17:00:47 -07:00
954e34cc91 docs: add angular.tw (Traditional Chinese) site to navigation.json (#30723)
PR Close #30723
2019-06-13 16:04:41 -07:00
e1f6d15387 release: cut the v8.0.1 release 2019-06-13 15:22:16 -07:00
cbb3794931 fix(docs-infra): enable only vertical scrolling for contributors bio (#30991)
- `auto` will enable scrolling only when needed
- `overflow-y` will ensure to keep the scrolling horizontally only

PR Close #30991
2019-06-12 11:47:13 -07:00
77a5790a9d docs: add platform to glossary (#30731)
PR Close #30731
2019-06-12 11:46:25 -07:00
4ca401c394 build(docs-infra): upgrade cli command docs sources to 7da10691d (#30999)
Updating [angular#8.0.x](https://github.com/angular/angular/tree/8.0.x) from [cli-builds#8.0.x](https://github.com/angular/cli-builds/tree/8.0.x).

##
Relevant changes in [commit range](e567d15ae...7da10691d):

**Modified**
- help/build.json

##

PR Close #30999
2019-06-12 11:45:07 -07:00
3dcd5ebdbc fix(ivy): unable to bind to implicit receiver in embedded views (#30994)
To provide some context: The implicit receiver is part of the
parsed Angular template AST. Any property reads in bindings,
interpolations etc. read from a given object (usually the component
instance). In that case there is an _implicit_ receiver which can also
be specified explicitly by just using `this`.

e.g.

```html
<ng-template>{{this.myProperty}}</ng-template>
```

This works as expected in Ivy and View Engine, but breaks in case the
implicit receiver is not used for property reads. For example:

```html
<my-dir [myFn]="greetFn.bind(this)"></my-dir>
```

In that case the `this` will not be properly translated into the generated
template function code because the Ivy compiler currently always treats
the `ctx` variable as the implicit receiver. This is **not correct** and breaks
compatibility with View Engine. Rather we need to ensure that we retrieve
the root context for the standalone implicit receiver similar to how it works
for property reads (as seen in the example above with `this.myProperty`)

Note that this requires some small changes to the `expression_converter`
because we only want to generate the `eenextContent()` instruction if the
implicit receiver is _actually_ used/needed. View Engine determines if that is the case by recursively walking through the converted output AST and
checking for usages of the `o.variable('_co')` variable ([see here][ve_check]). This would work too for Ivy, but involves most likely more code duplication
since templates are isolated in different functions and it another pass
through the output AST for every template expression.

[ve_check]: 0d6c9d36a1/packages/compiler/src/view_compiler/view_compiler.ts (L206-L208)

Resolves FW-1366.

**NOTE**: Patch version of 58be2ff884
(#30897)

PR Close #30994
2019-06-12 11:44:11 -07:00
49307f0595 fix(bazel): do not modify tsconfig.json (#30984)
This is a patch PR for https://github.com/angular/angular/pull/30877

PR Close #30984
2019-06-11 15:40:39 -07:00
762fc28fee feat(docs-infra): layout ui polish (#30883)
PR Close #30883
2019-06-11 14:20:36 -07:00
338e58c278 docs: use const in dynamic-component-loader example (#30888)
Use const instead of let. Some of the variables are never reassigned, so it is preferred to use const over let

PR Close #30888
2019-06-11 14:20:00 -07:00
7e2ed89208 docs: fix a grammar mistake (#30949)
Grammar mistake is in the JsonPipe section
PR Close #30949
2019-06-11 14:19:17 -07:00
56a3dcf44c build(docs-infra): upgrade cli command docs sources to e567d15ae (#30971)
Updating [angular#8.0.x](https://github.com/angular/angular/tree/8.0.x) from [cli-builds#8.0.x](https://github.com/angular/cli-builds/tree/8.0.x).

##
Relevant changes in [commit range](d09f130ce...e567d15ae):

**Modified**
- help/build.json
- help/generate.json
- help/new.json
- help/serve.json
- help/test.json

##

PR Close #30971
2019-06-11 14:17:32 -07:00
501bacdcf6 build: update golden for //packages/core/test/bundling/injection:symbol_test (#30965)
PR Close #30965
2019-06-11 10:54:28 -07:00
c5f2979a87 build(bazel): update to nodejs rules 0.31.1 & bazel 0.26.1 (#30965)
* entry_point attribute of nodejs_binary & rollup_bundle is now a label
* nodejs rules 0.30.1 has new feature to symlink node_modules with yarn_install and bazel 0.26.0 includes new managed_directories feature which enables this
* Symlinking of node_modules for yarn_install temporarily disabled (except for integration/bazel) until the fix for https://github.com/bazelbuild/bazel/issues/8487 makes it into a future bazel release. This is needed to work-around issue: yarn_install & npm_install with managed directories can't handle deleted or manually regenerated node_modules folder [https://github.com/bazelbuild/rules_nodejs/issues/802]. Underlying issue has been fixed in Bazel https://github.com/bazelbuild/bazel/issues/8487 but hasn't landed in a release yet

PR Close #30965
2019-06-11 10:54:28 -07:00
fe02462b5f build(docs-infra): update @angular/* to v8.1.0-next.1 and @angular/material to v8.0.0 (#30935)
PR Close #30935
2019-06-11 00:11:36 +00:00
3000d19ad1 build(docs-infra): update @angular/cli to v8.0.2 (#30935)
This restores named lazy chunks, which were broken during beta/rc (i.e.
the lazy chunks were named 0/1/2/...).

PR Close #30935
2019-06-11 00:11:36 +00:00
dcf9f05c9a docs: use Node.js consistently (#30934)
PR Close #30934
2019-06-11 00:09:49 +00:00
ba56f3c15b refactor(docs-infra): avoid hard-coding URLs to redirect on archive mode (#30894)
Related discussion:
https://github.com/angular/angular/pull/30894#pullrequestreview-246731995

PR Close #30894
2019-06-11 00:07:43 +00:00
865ad56e9a fix(docs-infra): do not redirect docs URLs on archive deployments (#30894)
To avoid showing outdated info (such as events, resources, etc.) but
still allow people to see docs for older versions, we redirect
non-documentation URLs to `/docs`. Recently(-ish) we have added
documentation content under the `/cli/...` and `/start/...`
path-prefixes, but we haven't added them to the list of documentation
URLs that should not be redirected. As a result, on archive deployments
(e.g. https://v7.angular.io/cli), they are redirected to `/docs`, making
it impossible to see the documentation for these versions (unless you
know about the `?mode=stable` work-around).

This commit fixes it by adding `cli` and `start` to the list of
documentation URLs that are excluded from redirection.

PR Close #30894
2019-06-11 00:07:43 +00:00
5cda2a041b refactor(docs-infra): make archive redirection tests DRY (#30894)
PR Close #30894
2019-06-11 00:07:43 +00:00
6a484853a9 build: update rules_nodejs and clean up bazel warnings (#30370) (#30763)
Preserve compatibility with rollup_bundle rule.
Add missing npm dependencies, which are now enforced by the strict_deps plugin in tsc_wrapped

PR Close #30370

PR Close #30763
2019-06-10 23:58:54 +00:00
e6ac289518 build: update to Bazel 0.26 (#30370) (#30763)
PR Close #30370

PR Close #30763
2019-06-10 23:58:54 +00:00
4e8614bb92 fix(common): expose the HttpUploadProgressEvent interface as public API (#30852)
Fixes #30814

PR Close #30852
2019-06-07 08:47:48 -07:00
9ace748d3a docs: add dev.to link to the help section (#30873)
PR Close #30873
2019-06-07 08:47:02 -07:00
08c38a1f99 fix(service-worker): avoid uncaught rejection warning when registration fails (#30876)
Service worker API `navigator.serviceWorker.register` can fail in multiple ways.
For example, in Chrome, with an unstable network connection you can have the
following error: `An unknown error occurred when fetching the script.`

In the current state, it creates an `Uncaught (in promise) TypeError:` style of
error, which cannot be caught by the user on his own.

I think it's better to log the error over raising an error that cannot be
caught.

PR Close #30876
2019-06-07 08:46:26 -07:00
9aeef0afdb build(docs-infra): fail hard if the CLI source is not what we expect (#30901)
Previously we just logged a warning but we should fail
to prevent silently allowing the docs to look wrong if
something changes on the CLI side of things.

PR Close #30901
2019-06-07 08:45:48 -07:00
8aef446373 build(docs-infra): upgrade cli command docs sources to d09f130ce (#30909)
Updating [angular#8.0.x](https://github.com/angular/angular/tree/8.0.x) from [cli-builds#8.0.x](https://github.com/angular/cli-builds/tree/8.0.x).

##
Relevant changes in [commit range](e8bdfe6b9...d09f130ce):

**Modified**
- help/serve.json

##

PR Close #30909
2019-06-07 08:44:42 -07:00
f7ee91a17c build(docs-infra): remove unneeded allowEmptyCodegenFiles option in Ivy mode (#30911)
Previously, when switching to Ivy mode (e.g. to run tests on CI), we had
to add `allowEmptyCodegenFiles: true` to the `angularCompilerOptions` in
`tsconfig.app.json`.

This isn't necessary any more (potentially since we switched to dynamic
imports for loading lazy modules in #30704), so this commit removes it
from the `switch-to-ivy.js` script.

PR Close #30911
2019-06-07 08:43:50 -07:00
8ae0afd3f8 fix(ivy): ngcc - remove unused import to make linting pass (#30914)
The failure is caused by 65f20107f. The unused [`writeFile` import][1]
seems to be a result of merge conflict resolution (since it is not
present on the original PR (#30831).

[1]: 65f20107fe (diff-4840f884874632c2fbfdb64a26213396R9)

PR Close #30914
2019-06-07 08:43:19 -07:00
be82270493 feat(docs-infra): white background and corresponding figure updates (#28396)
PR Close #28396
2019-06-06 13:48:16 -07:00
4cef2c1236 build(docs-infra): fix CLI command github links (#30889)
The "view" links were broken because the version used to
compute the git tag for the GitHub URL included a build SHA.
Now we clean that off before using it in the URL.

The links are to the JSON schema that defines the documentation for
the command. This is accurate but confusing because the content for the
long description is stored in a separate markdown file referenced from this
schema file.
This commit adds a second set of links for the long description, if it exists,
which links directly to the markdown file.

Closes #30700

PR Close #30889
2019-06-06 08:49:38 -07:00
26e3615e19 fix(core): TypeScript related migrations should cater for BOM (#30719)
fix(@schematics/angular): TypeScript related migrations should cater for BOM

In the CLI `UpdateRecorder` methods such as `insertLeft`, `remove` etc.. accepts positions which are not offset by a BOM. This is because when a file has a BOM a different recorder will be used https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/schematics/src/tree/recorder.ts#L72 which caters for an addition offset/delta.

The main reason for this is that when a developer is writing a schematic they shouldn't need to compute the offset based if a file has a BOM or not and is handled out of the box.

Example
```ts
recorder.insertLeft(5, 'true');
```

However this is unfortunate in the case if a ts SourceFile is used and one uses `getWidth` and `getStart` method they will already be offset by 1, which at the end it results in a double offset and hence the problem.

Fixes #30713

PR Close #30719
2019-06-06 08:44:56 -07:00
65f20107fe fix(ivy): ngcc - use spaces in overwritten package.json content for readability (#30831)
When ngcc processes an entrypoint, it updates `package.json` with
metadata about the processed format. Previously, it overwrote the
`package.json` with the stringified JSON object without spaces. This
made the file difficult to read (for example when looking at the file
while debugging an ngcc failure).

This commit fixes it by using spaces in the new `package.json` content.

PR Close #30831
2019-06-05 21:24:47 -07:00
5a7bcd1862 fix(bazel): Load global stylesheet in dev and prod (#30879)
Global stylesheet should be injected as a <link> tag in index.html for
both dev and prod app.

PR Close #30879
2019-06-05 21:20:59 -07:00
152ea36c80 build: unable to run build-packages-dist script on windows (#30853)
Currently it's not possible to run the `./scripts/build-packages-dist.sh` script on Windows because
`bazel query` returns CRLF line-endings which result on array expansion in Bazel target names
that end with a carriage return (e.g. `//packages/core\r`). This then results in a build failure where
Bazel complains that target names should not end with a carriage return.

In order to fix this, we just strip off the carriage return line-endings from the bazel query stdout. Ideally
the script will be ported to a plain Node script eventually, but for now it prevents Windows users from
building the release packages and the simple workaround seems reasonable and sufficient.

PR Close #30853
2019-06-05 09:05:29 -07:00
ea2adb104b docs: correct typos and formatting in the Getting Started guide (#30758)
PR Close #30758
2019-06-04 13:37:27 -07:00
19caace2ab docs(service-worker): mention that HTTPS is required, unless on localhost (#30847)
Fixes #30823

PR Close #30847
2019-06-04 12:03:12 -07:00
ccc1c27461 refactor: Move away from index signature based "updateCache". (#30518)
We're deprecating the index signature overloads in favor of using a Map.

PR Close #30518
2019-06-04 12:02:13 -07:00
97268b95f7 docs: update example dependencies to 8.x release (#30755)
PR Close #30755
2019-06-04 11:53:56 -07:00
7c41abe64a docs: rename component for constructor example (#30845)
PR Close #30845
2019-06-04 11:52:58 -07:00
991e138650 fix(ivy): unable to project into multiple slots with default selector (#30803)
With View engine it was possible to declare multiple projection
definitions and to programmatically project nodes into the slots.

e.g.

```html
<ng-content></ng-content>
<ng-content></ng-content>
```

Using `ViewContainerRef#createComponent` allowed projecting
nodes into one of the projection defs (through index)

This no longer works with Ivy as the `projectionDef` instruction only
retrieves a list of selectors instead of also retrieving entries for
reserved projection slots which appear when using the default
selector multiple times (as seen above).

In order to fix this issue, the Ivy compiler now passes all
projection slots to the `projectionDef` instruction. Meaning that
there can be multiple projection slots with the same wildcard
selector. This allows multi-slot projection as seen in the
example above, and it also allows us to match the multi-slot node
projection order from View Engine (to avoid breaking changes).

It basically ensures that Ivy fully matches the View Engine behavior
except of a very small edge case that has already been discussed
in FW-886 (with the conclusion of working as intended).

Read more here: https://hackmd.io/s/Sy2kQlgTE

NOTE: This is the patch version of #30561

PR Close #30803
2019-06-03 11:44:44 -07:00
d00b421402 docs: fix quickstart link in readme (#30807)
PR Close #30807
2019-06-03 11:43:59 -07:00
06ffed5141 docs: document UrlTree in guard return type in cheatsheet (#30822)
Add UrlTree to the types of returned values in guard methods

PR Close #30822
2019-06-03 11:43:26 -07:00
5a15126520 docs(core): fix typo in style bindings comment (#30661)
PR Close #30661
2019-06-03 09:01:06 -07:00
9e4b2f1a4f docs: fix a small typo in injectable decorator description (#30785)
PR Close #30785
2019-06-03 08:56:22 -07:00
393529d3b5 docs: update example references from "my-app" to "app-root" (#30789)
"app" is the default prefix for CLI projects when generating components.
This updates our examples to conform that that default

Closes #19778

PR Close #30789
2019-06-03 08:55:39 -07:00
81b75590d7 docs(docs-infra): compile module first for Ivy when loading element modules (#30704)
In View Engine, NgModule factories are created for each NgModule and loaded when the module is requested. Ivy doesn't generate the
factories by design and only loads the module class, so it must be compiled after being loaded.

PR Close #30704
2019-05-31 15:24:23 -07:00
151f0f4b2c refactor(docs-infra): update loading of custom elements to use dynamic import syntax (#30704)
Removes the usage of `NgModuleFactoryLoader` and string-based imports for lazy loading.

PR Close #30704
2019-05-31 15:24:23 -07:00
f88f941008 docs: increase color contrast on elements in tutorial
This increases the color contrast of elements in the tutorial (parts 1-6)
in order to meet WCAG 2.0 AA standards.
2019-05-31 15:23:33 -07:00
0e17958640 fix(docs-infra): add v7 in versions dropdown (#30775)
Fixes #30769

PR Close #30775
2019-05-31 15:19:54 -07:00
e82b45c8a7 docs(docs-infra): remove deprecated Buffer usage from stackblitz builder (#30369)
Fixes #30364

PR Close #30369
2019-05-31 09:56:23 -07:00
8422ef2a93 fix(docs-infra): update tooltip of events link (#30643)
PR Close #30643
2019-05-31 09:50:45 -07:00
cdf586d0d2 build(docs-infra): upgrade cli command docs sources to e8bdfe6b9 (#30777)
Updating [angular#8.0.x](https://github.com/angular/angular/tree/8.0.x) from [cli-builds#8.0.x](https://github.com/angular/cli-builds/tree/8.0.x).

##
Relevant changes in [commit range](9a3d36c98...e8bdfe6b9):

**Modified**
- help/update.json

##

PR Close #30777
2019-05-31 09:45:09 -07:00
3828c89792 ci: add reviewer group for deprecations guide (#30722)
PR Close #30722
2019-05-30 20:45:59 -07:00
0f352b6350 docs: add final release date and update future schedule (#30712)
PR Close #30712
2019-05-30 19:39:24 -07:00
06bdecffb9 docs: remove mention of project settings from analytics (#30701)
This settings are not yet implemented and will be available in 8.1.

PR Close #30701
2019-05-30 13:42:35 -04:00
99ddec152b docs(ivy): fix symbol in example AST (#30745)
PR Close #30745
2019-05-30 13:41:52 -04:00
31aba96fcb docs: improve glossary for entry-point. (#29433)
PR Close #29433
2019-05-30 13:40:55 -04:00
facce2c9fd docs: fix typo in upgrade guide example (#30428)
An code snippet from a `package.json` file used `script`
rather than `scripts`.

Fixes #30418

PR Close #30428
2019-05-30 13:40:07 -04:00
edaf058548 docs: fix closing tags in deprecation summary (#30735)
fix closing tags in "Cannot assign to template variables" section

PR Close #30735
2019-05-30 13:38:54 -04:00
4bff2d0c8c docs: fix deprecation information (#30717)
PR Close #30717
2019-05-30 13:38:34 -04:00
cfc608aaf3 docs: merge duplicated platform-webworker content in Deprecation Guide (#30651)
fix issue of duplicate anchors/ids

PR Close #30651
2019-05-30 13:36:30 -04:00
6d9f5fcddb docs(elements): move clarification about custom elements (#30594)
Moved clarification that "custom elements" are a subtype of Web Components to the first use of the term "custom elements"

PR Close #30594
2019-05-30 13:35:15 -04:00
b19a05c25a docs(common): fix typo in ngSwitch directive description (#30483)
PR Close #30483
2019-05-30 13:34:22 -04:00
bd75b3b7b3 docs: fix the sequence of creating class in HTTP tutorial (#30566)
For more accurate procedure of creating a class in the "Tour of Heroes" app, updated the sequence of creating one class.

PR Close #30566
2019-05-30 13:32:53 -04:00
1c67b9063b docs: clarify usage of using /deep/ in component styles guide (#30452)
Updated the description regarding the (deprecated) /deep/ pseudo-selector to clarify its propensity to bleed styles across components and its solution

closes #29967

PR Close #30452
2019-05-30 13:32:32 -04:00
9a9ae60e0e docs: code sample closing in ivy.md (#30711)
PR Close #30711
2019-05-30 13:32:11 -04:00
ae6fa9260a docs: change wording for more clarity in TypeScript Configuration guide (#30748)
"You need to do nothing" indicates the presence of an action (the action of doing nothing) while the goal is to tell the user that no action is required from them. I think "You don’t need to do anything" is better suitable in this context.

PR Close #30748
2019-05-30 13:31:24 -04:00
f8fa2f2a6c docs(core): template-var-assignment schematic should link to deprecation guide (#30702)
Instead of linking to a markdown file explaining what the migration warnings
are about, we should link to the deprecation guide which now also contains
an entry for that schematic. This makes the deprecation explanations
consistent and more centralized.

PR Close #30702
2019-05-29 13:50:35 -04:00
f3ee9a6144 docs: add note to platform-webworker deprecation (#30705)
PR Close #30705
2019-05-28 16:37:58 -07:00
d076c51455 test: improve language service tests performance (#30683)
With this change we reduce the amount of IO operations. This is especially a huge factor in windows since IO ops are slower.

With this change mainly we cache `existsSync` and `readFileSync` calls

Here's the results

Before
```
//packages/language-service/test:test
INFO: Elapsed time: 258.755s, Critical Path: 253.91s
```

After
```
//packages/language-service/test:test
INFO: Elapsed time: 66.403s, Critical Path: 63.13s
```

PR Close #30683
2019-05-28 16:15:02 -07:00
38a7e2a775 release: cut the v8.0.0 release 2019-05-28 10:14:07 -07:00
c61c14a127 docs: remove core.module.ts from file tree in style guide (#30679)
PR Close #30679
2019-05-28 09:27:49 -07:00
652b0959a8 docs: add missing preposition (#30691)
You need do nothing -> You need to do nothing
PR Close #30691
2019-05-28 09:27:24 -07:00
002fbddcf1 docs: add default AOT to migrating projects to Ivy (#30697)
Followup to https://github.com/angular/angular/pull/29380, https://github.com/angular/angular/pull/30238, https://github.com/angular/angular-cli/pull/14537.

PR Close #30697
2019-05-28 09:27:02 -07:00
4761d40a41 docs: fix typo in a declaration alert (#30545)
Co-Authored-By: CaerusKaru <caerus.karu@gmail.com>
PR Close #30545
2019-05-28 09:25:10 -07:00
608e0f0d67 docs: add dynamic import allowed syntax to the deprecation guide (#30545)
PR Close #30545
2019-05-28 09:25:10 -07:00
45718b3b21 build(docs-infra): upgrade cli command docs sources to 9a3d36c98 (#30609)
Updating [angular#8.0.x](https://github.com/angular/angular/tree/8.0.x) from [cli-builds#8.0.x](https://github.com/angular/cli-builds/tree/8.0.x).

##
Relevant changes in [commit range](fa429865e...9a3d36c98):

**Modified**
- help/analytics.json
- help/build.json
- help/e2e.json
- help/serve.json
- help/test.json
- help/xi18n.json

##

PR Close #30609
2019-05-24 18:19:17 -04:00
b5756bcc39 docs(bazel): remove out of date known issue with Webstorm (#30650)
https://github.com/bazelbuild/intellij/issues/246 was resolved in 2018

PR Close #30650
2019-05-24 13:51:29 -04:00
60f0462049 docs: drop coding conventions from style guide (#30334)
PR Close #30334
2019-05-24 13:46:12 -04:00
9fd22959d3 docs: add Michael Hladky to GDE resources (#30596)
PR Close #30596
2019-05-24 13:40:34 -04:00
d5dd907396 docs(core): static-query migration should use permalink for migration guide (#30649)
8479cb4233 updated the static-query migration
to refer to the new guide on AIO. Unfortunately these URLs are currently not
valid as the guide is only available on `next.angular.io` right now. In order to
make the link work permanently (e.g. if we eventually remove the guide in future
major versions), we use the permalink from the `v8` subdomain.

PR Close #30649
2019-05-24 10:08:17 -05:00
5a6bf7de0e docs: update link to static queries in changelog (#30649)
PR Close #30649
2019-05-24 10:08:16 -05:00
d135bb5e6e release: cut the v8.0.0-rc.5 release 2019-05-23 22:32:48 -07:00
8b9a3e49f2 docs(core): add more info to static query guide (#30646)
PR Close #30646
2019-05-23 22:14:50 -07:00
44e55fe2e4 docs(core): update static query schematic with guide link (#30646)
PR Close #30646
2019-05-23 22:14:50 -07:00
063cc308b6 docs(core): update deprecations guide (#30644)
PR Close #30644
2019-05-23 16:25:49 -07:00
c567135dd5 docs(core): add migration guide for static queries (#30644)
PR Close #30644
2019-05-23 16:25:49 -07:00
361f181c8c feat(platform-webworker): deprecate platform-webworker (#30642)
DEPRECATION:

platform-webworker has been around since the initial release of Angular
version 2. It began as an experiment to leverage Angular's rendering
architecture and try something different: to run an entire web application
in a web worker.

We've learned a lot from this experiment, and have come to the conclusion
that pushing entire applications to run in a web worker is not a recipe for
success for most applications. This is due to a number of unresolved issues,
including:

* Poor or non-existent support for web worker APIs in web crawlers/indexers.
* Poor support in build and bundling tooling.

As a result, as of Angular version 8, we are deprecating the
`platform-webworker` APIs in Angular. This consists of both NPM packages,
`@angular/platform-webworker` and `@angular/platform-webworker-dynamic`.

Going forward, we will focus our efforts related to web workers around their
primary use case of offloading CPU-intensive but not critical work.

FW-1339 #resolve

PR Close #30642
2019-05-23 15:09:49 -07:00
b40844523b feat(core): deprecate integration with the Web Tracing Framework (WTF) (#30642)
DEPRECATION:

Angular previously has supported an integration with the Web Tracing
Framework (WTF) for performance testing of Angular applications. This
integration has not been maintained and likely does not work for the
majority of Angular applications today. As a result, we are deprecating
the integration in Angular version 8.

This deprecation covers the following public APIs:
* `WtfScopeFn`
* `wtfCreateScope`
* `wtfStartTimeRange`
* `wtfEndTimeRange`
* `wtfLeave`

FW-1338 #resolve

PR Close #30642
2019-05-23 15:09:49 -07:00
c8af830ec8 fix(core): require 'static' flag on queries in typings (#30641)
This commit makes the static flag on @ViewChild and @ContentChild required.

BREAKING CHANGE:

In Angular version 8, it's required that all @ViewChild and @ContentChild
queries have a 'static' flag specifying whether the query is 'static' or
'dynamic'. The compiler previously sorted queries automatically, but in
8.0 developers are required to explicitly specify which behavior is wanted.
This is a temporary requirement as part of a migration; see
https://angular.io/guide/static-query-migration for more details.

@ViewChildren and @ContentChildren queries are always dynamic, and so are
unaffected.

PR Close #30641
2019-05-23 15:09:20 -07:00
e2c9ddb33e test(core): update query-specific tests in core (#30626) (#30641)
PR Close #30626

PR Close #30641
2019-05-23 15:09:20 -07:00
04196ec2d0 test(compiler): update examples and compiler tests (#30626) (#30641)
PR Close #30626

PR Close #30641
2019-05-23 15:09:20 -07:00
7323072c5c test(common): update common tests to use static flag (#30626) (#30641)
PR Close #30626

PR Close #30641
2019-05-23 15:09:20 -07:00
f0c5400cab test(core): update core tests (unrelated to queries) to use static flag (#30626) (#30641)
PR Close #30626

PR Close #30641
2019-05-23 15:09:19 -07:00
3f2f937c9f docs: add v8 deprecations (#30598)
PR Close #30598
2019-05-23 13:31:14 -07:00
256fe2421a refactor(core): static-query migration should warn about syntax failures (#30628)
Currently if a project has source-files with syntax failures and the migration
has been started on a broken project, we silently migrate *as much as possible*,
but never notify the developer that the project was in a broken state and that
he can re-run the migration after the failures are fixed.

Additionally the template strategy does not need to exit gracefully if it detects
Angular semantic diagnostics on generated files (template type checking). These
diagnostics are not relevant for the query timing analysis.

PR Close #30628
2019-05-23 10:31:49 -07:00
e6f27bcb0c refactor(core): static-query migration should always use template strategy (#30628)
We are removing the prompt for the `static-query` migration and make the
template strategy the migration strategy for the migration. The usage
strategy is good for best-practices, but for now we want to ensure that
the migration is a seamless as possible and that is only achievable my
re-using the same logic that View Engine uses for determining the
timing of a query.

PR Close #30628
2019-05-23 10:31:48 -07:00
8abcf04a5e docs: update simple stackblitz deployment instructions (#30465)
PR Close #30465
2019-05-22 16:29:45 -07:00
bf38df4eb9 fix(bazel): allow ts_library interop with list-typed inputs (#30600)
_compile_action should take a list since we compute it within one node in the build graph
This needs to be cleaned up since Bazel is getting stricter with
disallowing iteration over depsets

PR Close #30600
2019-05-22 16:22:11 -07:00
79a025306a docs: add new cli builder api guide (#29964)
PR Close #29964
2019-05-22 16:19:54 -07:00
62c936aa49 docs: update node and typescript versions mentioned in docs (#30601)
PR Close #30601
2019-05-22 16:17:42 -07:00
77e1b34d91 docs: update file structure and workspace config for v8 (#30595)
PR Close #30595
2019-05-22 11:20:18 -07:00
26cb128b3c build: remove concurrency from e2e tests (#30547)
There appears to be a race condition with the package.json files during test runs

PR Close #30547
2019-05-22 10:41:19 -07:00
fdbe07982a refactor: Move from Δ back to ɵɵ (#30547)
PR Close #30547
2019-05-22 10:41:19 -07:00
c0e3209915 build: update base SHA for rebase on merge-pr script 2019-05-22 10:40:34 -07:00
70880f0cea refactor(core): migrations should parse cli workspace config as json5 (#30582)
Currently we try to parse CLI workspace configurations gracefully by
using the native `JSON.parse()` method. This means that the CLI workspace
configuration needs to follow the strict JSON specification because otherwise
the migrations would not be able to find TypeScript configurations in the CLI
project where JSON5 workspace configurations are supported.

In order to handle such workspace configurations, we leverage the JSON
parsing logicfrom the `@angular-devkit/core` which is also used by the CLI.

PR Close #30582
2019-05-21 17:26:23 -07:00
221a5ba634 build(docs-infra): upgrade cli command docs sources to fa429865e (#30531)
Updating [angular#8.0.x](https://github.com/angular/angular/tree/8.0.x) from [cli-builds#8.0.x](https://github.com/angular/cli-builds/tree/8.0.x).

##
Relevant changes in [commit range](d46eb367f...fa429865e):

**Modified**
- help/update.json

##

PR Close #30531
2019-05-21 17:09:18 -07:00
68b08cf782 docs: deprecations summary fix api heading level, remove inject, add index by version (#30400)
PR Close #30400
2019-05-21 13:52:46 -07:00
10560a0872 docs: delete double dashes on ng command in testing guide (#30551)
Closes #30550

PR Close #30551
2019-05-21 13:12:48 -07:00
561e01ddfd fix(core): temporarily remove @deprecated jsdoc tag for a TextBed.get overload (#30514)
PR #29290 introduced a new `TestBed.get` signature and deprecated the existing one.
This raises a lot of TSLint deprecation warnings in projects using a strict TS config (see #29905 for context), so we are temporarily removing the `@deprecated` annotation in favor of a plain text warning until we properly fix it.

Refs #29905
Fixes FW-1336

PR Close #30514
2019-05-21 13:11:22 -07:00
d1345c78f0 docs(docs-infra): add common/upgrade to authors package for API docs (#30567)
This fixes an issue where the common/upgrade packge isn't included
on page reload when changes are made to the common/upgrade package

PR Close #30567
2019-05-21 13:09:10 -07:00
276f9067c8 docs(common): update API docs for unified location service for upgrading (#30567)
PR Close #30567
2019-05-21 13:09:09 -07:00
0e90a4263b docs: document the PR action: rerun CI at HEAD label in TRIAGE_AND_LABELS.md (#30171)
Related to #29098.

PR Close #30171
2019-05-21 13:07:38 -07:00
e4cc1398aa docs: document the PR action: review label in TRIAGE_AND_LABELS.md (#30171)
PR Close #30171
2019-05-21 13:07:38 -07:00
8d1f993ceb docs: add info about who adds/removes labels in TRIAGE_AND_LABELS.md (#30171)
PR Close #30171
2019-05-21 13:07:38 -07:00
df1ab49893 docs: fix spelling of 'its' (#30455)
PR Close #30455
2019-05-21 13:07:13 -07:00
df03fec8a6 refactor(ivy): rewrite flatten function to be more memory efficient (#30468)
The `flatten` function used `concat` and `slice` which created a lot of intermediary
object allocations. Because `flatten` is used from query any benchmark which
used query would exhibit high minor GC counts.

PR Close #30468
2019-05-21 13:06:24 -07:00
c01cae22e1 docs: add section to upgrade guide on lazy loading AngularJS (#30541)
PR Close #30541
2019-05-21 13:06:02 -07:00
5a46f94987 fix(core): remove deprecated TestBed.deprecatedOverrideProvider API (#30576)
BREAKING CHANGE

In PR #19558, we fixed a bug in `TestBed.overrideProvider` where
eager providers were not being instantiated correctly. However,
it turned out that since this bug had been around for quite a bit,
many apps were relying on the broken behavior where the providers
would not be instantiated. To assist in the transition, the
`TestBed.deprecatedOverrideProvider` method was temporarily
introduced to mimic the old behavior so that apps would have a
longer time period to migrate their code.

2 years and 3 versions later, it is time to remove the temporary
method. This commit removes `TestBed.deprecatedOverrideProvider`
altogether. Any usages of `TestBed.deprecatedOverrideProvider`
should be replaced with `TestBed.overrideProvider`. This may mean
that providers that were not created before will now be instantiated,
which could mean that your tests need to provide more mocks or stubs
for the dependencies of the newly instantiated providers.

PR Close #30576
2019-05-21 12:37:18 -07:00
5716605d52 ci(docs-infra): fix test_docs_examples_ivy job (#30593)
Context:
As part of the `test_docs_examples_ivy` job, we run 5 concurrent builds
on each VM (each for a different example/project). Additionally, all
example projects share the same `node_modules/` (via a symlink to
`aio/tools/examples/shared/node_modules/`), so all concurrent builds
operate on the same files.

Previously, we pre-ran ngcc with `--properties module` to process the
fesm5 bundles. Since we have switched to es2015 in 661a57d9e, we now
need the esm2015 bundles. As a result, the initial ngcc run is
redundant and ngcc runs again during each build (to process the fesm2015
bundles). Since there are 5 concurrent builds, we often end up with
multiple ngcc instances processing the same package and trying to write
to the same directories at the same time, causing a
`file already exists` error

This commit fixes it by pre-processing the esm2015 bundles, so there is
no need to re-run ngcc during each concurrent build.

Fixes #30577

PR Close #30593
2019-05-21 12:32:58 -07:00
8043e3131c docs: use dynamic import syntax in examples using lazy loading (#30563)
PR Close #30563
2019-05-21 09:09:35 -07:00
54f7245081 docs(changelog): remove docs-infra changes (#25833)
PR Close #25833
2019-05-21 09:06:46 -07:00
5de24b6dfe docs: move instructions to see changes after the error is fixed in the tutorial (#30529)
docs: List only appears after the error is fixed

When the error happens, the list is not displayed too. Once the error is removed, the heroes list appears, so we can click and see the details.

PR Close #30529
2019-05-21 09:03:49 -07:00
4dc4d7f30a docs: remove gender prefixes from examples (#29972)
PR Close #29972
2019-05-20 16:43:00 -07:00
fcea1a3c22 docs: improve consistency of style guide example (#30504)
The text for entry Style 04-10 of the style guide talks about
FilterTextService however, the example folder structure has the inversed
filename.

PR Close #30504
2019-05-20 16:42:16 -07:00
8bc4da8665 fix(bazel): ng test should run specific ts_web_test_suite (#30526)
PR closes https://github.com/angular/angular/issues/30191

PR Close #30526
2019-05-20 16:40:11 -07:00
a5a2d525ae docs: move old quick start content into new local setup guide (#29651)
PR Close #29651
2019-05-20 10:16:24 -07:00
4690dcecac build: add recommended config files for VSCode remote development (#30450)
Add some recommended config files to use (as is or as basis) for setting
up [remote development using docker containers][1] with VSCode. This is
an opt-in feature. See `.devcontainer/README.md` for more info.

The configuration can be further tweaked/improved, but is a good
starting point.

[1]: https://code.visualstudio.com/docs/remote/containers

PR Close #30450
2019-05-20 10:13:53 -07:00
722b2fa6ed feat(common): stricter types for SlicePipe (#30156)
Adds overloads to the `transform` methods of `SlicePipe`,
to have better types than `any` for `value` and `any` as a return.
With this commit, using `slice` in an `ngFor` still allow to type-check the content of the `ngFor`
with `fullTemplateTypeCheck` enabled in Ivy:

    <div *ngFor="let user of users | slice:0:2">{{ user.typo }}</div>
                                                        |
                                                        `typo` does not exist on type `UserModel`

whereas it is currently not catched (as the return of `slice` is `any`) neither in VE nor in Ivy.

BREAKING CHANGE
`SlicePipe` now only accepts an array of values, a string, null or undefined.
This was already the case in practice, and it still throws at runtime if another type is given.
But it is now a compilation error to try to call it with an unsupported type.

PR Close #30156
2019-05-17 14:21:37 -07:00
124d1abf19 docs: update docs example dependencies to version 8 (#30385)
PR Close #30385
2019-05-17 14:16:56 -07:00
736d3ef820 docs: add kamil mysliwiec to GDE resources (#30508)
PR Close #30508
2019-05-17 13:32:44 -07:00
9b0ad347e1 test(platform-browser-dynamic): avoid swallowing error in CachedResourceLoader test (#30515)
Previously, in order to assert that the promise was not resolved, an
error was thrown when the promise was resolved successfully. At the
same, `.catch()` was used to silence the (expected) promise rejection.
However, the chained `.catch()` handler would also catch (and swallow)
the error thrown on resolving the promise, making the test pass, even if
the promise was not rejected.

This commit fixes it by ensuring that the error thrown on resolving the
promise is not caught by the rejection handler.

PR Close #30515
2019-05-16 20:14:05 -07:00
d2598ace0a test(platform-browser-dynamic): make CachedResourceLoader tests more reliable (#30515)
Previously, [this test][1] would occasionally fail (e.g. on CI) with
"Template cache was not found in $templateCache". This was due to a
combination of:
1. [That test][2] (which removes the cache) being run right before the
   failing test.
2. The async `TestBed.compileComponents()` operation run in the
   `beforeEach()` block (which sets the cache) not having completed
   before the `it()` block.

This commit fixes the issue by ensuring the cache is always set, before
instantiating `CachedResourceLoader`.

This commit also moves some operations that are only needed in one test
from the `beforeEach()` block to that test's `it()` block.

[1]: 79903b1842/packages/platform-browser-dynamic/test/resource_loader/resource_loader_cache_spec.ts (L50)
[2]: 79903b1842/packages/platform-browser-dynamic/test/resource_loader/resource_loader_cache_spec.ts (L37)

Fixes #30499

PR Close #30515
2019-05-16 20:14:04 -07:00
4a25e4cf95 build(bazel): update to latest stable chromium 74 on osx and linux for karma under bazel (#30502)
We were on 69 for both of these platforms which is fairly old. This update also requires a temporary patch to the @bazel/karma npm package to disable chrome sandboxing on OSX as it is broken under Bazel as of chromium 73. Windows is still on Chromium 66 but updating this will require upstream changes to rules_webtesting as the archive name & executable name has changed as of 72 for Windows and hard-coded paths in rules_webtesting break things.

PR Close #30502
2019-05-16 14:38:15 -07:00
3f67bf208d docs: add link to location upgrade config (#30331)
PR Close #30331
2019-05-16 11:53:48 -07:00
d85476fd8c docs(docs-infra): add common/upgrade to API package sources (#30331)
Closes #30332

PR Close #30331
2019-05-16 11:53:43 -07:00
9763edf829 refactor(common): update argument length in UrlCodec.areEqual method and AngularJSUrlCodec.areEqual methods (#30331)
dgeni requires that method arguments be at least 2 characters long

PR Close #30331
2019-05-16 11:47:17 -07:00
b6ae54c547 docs: add section to upgrade guide on using the unified location service (#30331)
The LocationUpgradeModule provides a unified way of handling URL updates
across AngularJS and Angular.

PR Close #30331
2019-05-16 11:47:17 -07:00
3de26a84ff fix(bazel): Disable sandbox on Mac OS (#30460)
Removing the sandbox improves build time by almost 40%.

For a hello world (ng new) application:
ng build with sandbox: 22.0 seconds
ng build without sandbox: 13.3 seconds

PR Close #30460
2019-05-16 09:43:54 -07:00
8022d3691b feat(common): add ability to watch for AngularJS URL updates through onUrlChange hook (#30466)
The LocationShim (replacement for `$location`) was added to centralize dealing with the browser URL. Additionally, an `onUrlChange` method was added to Angular's Location service. This PR adds a corresponding method to the LocationShim so updates from AngularJS can be tracked in Angular.

PR Close #30466
2019-05-16 09:43:33 -07:00
581336a918 docs: fix typo in animations doc (#30457)
PR Close #30457
2019-05-15 14:26:12 -07:00
effc58086c docs: correct types in transform method to match specification. (#29812)
PR Close #29812
2019-05-15 14:24:20 -07:00
766615c8a1 docs: fix example "testing" app compilation (#30427)
PR Close #30427
2019-05-15 14:12:23 -07:00
ede4246663 docs: fix the payload in event-binding sample code (#30429)
after reading the context. there are  some clues to infer the payload should be the `item`, not `item.name`.
1.  EventEmitter<Item>.
2.  the desc say that:
The component defines a deleteRequest property that returns an EventEmitter. When the user clicks delete, the component invokes the delete() method, telling the EventEmitter to emit an **Item** object.

PR Close #30429
2019-05-15 14:12:02 -07:00
bb8a6abbf2 test(ivy): move render3 query tests to acceptance (#30382)
Moves all manual render3 query tests that use the `elementProperty`
instructions to TestBed acceptance tests.

PR Close #30382
2019-05-15 14:11:38 -07:00
32daa930d0 fix(router): type cast correctly for IE 11 bug breaking URL Unification when comparing objects (#30464)
PR #30393 corrected behavior where Object.keys sometimes returns an `undefined` value. However, the types didn't reflect this in the code. That fix actually missed one value that could return `undefined`. This PR corrects this by casting the types to what they can be in IE 11. This ensures the code behaves as it should when this edge case comes up.

PR Close #30464
2019-05-15 14:09:54 -07:00
b6aa99d3a7 release: cut the v8.0.0-rc.4 release 2019-05-15 12:19:51 -07:00
e10b213784 refactor(ivy): deprecate ɵɵinject and ɵɵdefineInjectable (#30467)
- They are to be removed before the end of RC

PR Close #30467
2019-05-15 11:40:33 -07:00
a67cf99b0c refactor(ivy): mark ΔdefineInjectable as codeGenApi. (#30467)
PR Close #30467
2019-05-15 11:40:33 -07:00
04d04fd147 refactor(ivy): replace ɵɵ with Δ (#30467)
PR Close #30467
2019-05-15 11:40:33 -07:00
17361d2b2c Revert "Revert "fix(router): fix a problem with router not responding to back button (#30160)" (#30320)" (#30344)
This reverts commit 8ced321bb6.

PR Close #30344
2019-05-15 10:14:48 -07:00
9b88920aa9 fix(router): ensure navigations start with the current URL value incase redirect is skipped (#30344)
In some cases where multiple navigations happen to the same URL, the router will not process a given URL. In those cases, we fall into logic that resets state for the next navigation. One piece of this resetting is to set the `browserUrlTree` to the most recent `urlAfterRedirects`i.

However, there was bug in this logic because in some cases the `urlAfterRedirects` is a stale value. This happens any time a URL won't be processed, and the previous URL will also not be processed. This creates unpredictable behavior, not the least of which ends up being a broken `back` button.

This PR kicks off new navigations with the current value the router assumes is in the browser. All the logic around how to handle future navigations is based on this value compared to the current transition, so it's important to kick off all new navigations with the current value so in the edge case described above we don't end up with an old value being set into `browserUrlTree`.

Fixes #30340
Related to #30160

PR Close #30344
2019-05-15 10:14:47 -07:00
b12e76d1d3 refactor: remove toplevel property accesses (#30470)
PR Close #30470
2019-05-15 10:00:12 -07:00
af001a8cbd test: add integration test for side effects (#30470)
This new tests keeps track of the known side effects for Angular ES modules.

PR Close #30470
2019-05-15 10:00:12 -07:00
db64b014f8 Revert "fix(core): CSS sanitizer now allows parens in file names (#30322)" (#30463)
This reverts commit 728db88280.

We're reverting this commit for now, until it can be subjected to a more
thorough security review.

PR Close #30463
2019-05-14 14:49:40 -07:00
7e34975bb0 refactor(core): improve messages for static-query migrations (#30458)
Slightly improves the messages for the static-query migration in order
to make the terminal output less verbose but more helpful. Unfortunately
we are limited in what we can print due to the devkit not providing much
utilities for printing good messages from a migration schematic.

PR Close #30458
2019-05-14 14:04:44 -07:00
0fa48e8c00 fix(core): static-query migration should not fallback to test strategy (#30458)
Currently if something fails in the selected strategy (e.g. AOT failures),
the migration currently accidentally falls back to the test strategy. This
is not helpful as we want to give developers the possibility to re-run
the migration after fixing potential AOT failures.

PR Close #30458
2019-05-14 14:04:44 -07:00
fde3f467e2 fix(core): static-query migration errors not printed properly (#30458)
Apparently the devkit logger is not able to properly print
out error objects, so we need to convert them to a string
before in order to make the error visible to the user.

This is not testable without an e2e test that validates the CLI
terminal output.

PR Close #30458
2019-05-14 14:04:44 -07:00
7b378a6920 docs: update ivy preview page (#30355)
PR Close #30355
2019-05-14 12:17:26 -07:00
3136d9ff2e fix(bazel): Use existing npm/yarn lock files (#30438)
This PR fixes Bazel builder to create yarn_install rule in WORKSPACE if
yarn.lock is present, otherwise npm_install rule if package-lock.json is
present. If none is present, default to yarn_install and create an empty
yarn.lock file.

PR closes https://github.com/angular/angular/issues/30164
PR closes https://github.com/angular/angular/pull/30359

PR Close #30438
2019-05-14 11:37:33 -07:00
325e6cf557 build(docs-infra): update http-server to 0.11.1 (#30401)
Fixes #30363

PR Close #30401
2019-05-14 09:55:47 -07:00
381d7c4e44 test(ivy): move render3 directive tests to acceptance (#30432)
Moves all manual render3 directive tests to TestBed acceptance
tests.

PR Close #30432
2019-05-14 09:37:01 -07:00
1b6f3c1ead test(ivy): move render3 renderer_factory tests to acceptance (#30435)
Moves all manual render3 tests which are located within the
`renderer_factory_spec.ts` file to acceptance tests. A few tests
that use Ivy-specific logic which is not replicable with `TestBed`
remain in the render3 folder (e.g. using `renderTemplate`)

Additionally migrated tests that assert the lifecycles of the
renderer_factory are set to *ivy only* as the lifecycle seems
to be different in Ivy. Tracked with: FW-1320

PR Close #30435
2019-05-14 09:36:24 -07:00
c38349127c fix(router): IE 11 bug can break URL unification when comparing objects (#30393)
This PR fixes an issue where IE 11 can return `undefined` in with an `Object.keys` call. Solution is to add a runtime check on the value. Based on the types being passed, this shouldn't be necessary, but is needed only for IE 11. Unit test doesn't work for this PR because it can't be replicated easily.

PR Close #30393
2019-05-13 11:40:43 -07:00
a4817729a2 test: fix ngtsc tests in windows (#30146)
This commit fixes the following test target in windows

```
//packages/compiler-cli/test/ngtsc:ngtsc
```

PR Close #30146
2019-05-13 11:06:13 -07:00
61c343e3eb test: fix several Bazel compiler tests in windows (#30146)
```
//packages/compiler-cli/test:ngc
//packages/compiler/test:test
```

This also address `node_modules` to the ignored paths for ngc compiler as otherwise the `ready` is never fired

Partially addresses #29785

PR Close #30146
2019-05-13 11:06:13 -07:00
24e6c1e80d release: ts_api_guardian (#30120)
PR Close #30120
2019-05-13 10:53:35 -07:00
42fc5c9b33 docs: change reference to jQuery programmers (#30386)
The section on Data Binding makes a reference to "any experienced jQuery programmer" which is a bit too narrow since there are also  programmers that write their front end in pure JavaScript.
PR Close #30386
2019-05-13 10:49:27 -07:00
33e7b285ca build(docs-infra): upgrade cli command docs sources to d46eb367f (#30415)
Updating [angular#8.0.x](https://github.com/angular/angular/tree/8.0.x) from [cli-builds#8.0.x](https://github.com/angular/cli-builds/tree/8.0.x).

##
Relevant changes in [commit range](cd7920355...d46eb367f):

**Modified**
- help/build.json
- help/e2e.json
- help/serve.json
- help/test.json
- help/xi18n.json

##

PR Close #30415
2019-05-13 10:28:18 -07:00
74afdc37da build: ignore .devcontainer/ directory (#30417)
This makes it easier to experiment with VSCode's
[remote development using docker containers][1] feature.

In the future, we may check in the necessary files for users to use this
feature, but for now ignoring the directory makes it easier play around
and evaluate the feature.

[1]: https://code.visualstudio.com/docs/remote/containers

PR Close #30417
2019-05-13 10:17:16 -07:00
3c1ffba0ad test(ivy): move pipe tests into acceptance (#30389)
Moves over the tests from `pipe_spec` into `acceptance`. Note that the two `WrappedValue` tests haven't been moved over, because impure pipes always throw "changed after checked" errors in `TestBed`. This seems to be consistent with ViewEngine.

PR Close #30389
2019-05-10 14:35:57 -07:00
14c0017db8 build: upgrade zone.js to 0.9.1 (#30260)
Close 30203

resolves the issue that zone-legacy XHR issue

PR Close #30260
2019-05-10 14:25:56 -07:00
4878f4890b build(docs-infra): ensure hidden cli commands are excluded from sitemap.xml (#30395)
Previously, the processor that excludes certain cli commands
(`filterHiddenCommand`) was being run after the `createSitemap`
processor, resulting in those commands to be present in `sitemap.xml`,
while the actual pages where missing. This also resulted in 404s, when
search engine crawlers tried to index the missing URLs.

This commit fixes it by ensuring that the `filterHiddenCommand`
processor is run before the `createSitemap` processor.

PR Close #30395
2019-05-10 11:56:39 -07:00
b7edef0cd3 docs: remove mention of chrome 41 from differential loading (#30390)
PR Close #30390
2019-05-10 11:55:12 -07:00
39fa937ab9 test(ivy): move output tests to acceptance (#30372)
Moves most of the tests in `output_spec` into `acceptance`. Note that one test is left in `render3`, because it's testing mixing in custom logic with instructions which we can't replicate using `TestBed`.

PR Close #30372
2019-05-10 09:27:57 -07:00
2977829c67 test(ivy): move content projection tests to acceptance (#30357)
Moves all manual `render3` content projection tests that use
the `ɵɵelementProperty` to acceptance tests. Additionally a
few other content projection tests were moved over to
acceptance. Eventually we'll be able to move all remaining
content projection tests to acceptance.

PR Close #30357
2019-05-10 09:18:37 -07:00
dbe845e048 test(ivy): use TestBed for render3 component tests (#30282)
PR Close #30282
2019-05-10 09:18:19 -07:00
e562acc884 feat(bazel): use rbe_autoconfig() and new container. (#29336)
After this PR is merged, maintainers no longer need to update .bazelrc
file, toolchain and platform related flags for RBE builds and tests
(unless there is a breaking change in Bazel related to those flags).

Maintainers just need to update the pin of @bazel-toolchains repo
regularly in the packages/bazel/package.bzl file according to
https://releases.bazel.build/bazel-toolchains.html to include the
latest checked-in toolchain configs. If rbe_autoconfig() cannot find
appropriate toolchain configs for the version of Bazel in the version of
@bazel_toolchains repo that is currently used by this project, it will pull
down the container and generate the configs on the fly as the beginning
of the build/test.

PR Close #29336
2019-05-09 14:58:34 -07:00
e295c6a0ae fix(core): static-query usage migration strategy should detect ambiguous query usage (#30215)
Currently we always just set the timing to `false` if we aren't
able to analyze a given call expression or new expression. e.g.

```ts
ngOnInit() {
  thirdPartyCallSync(() => this.query.doSomething())
}
```

In that case the `thirdPartyCallSync` function comes from the `node_modules`
and is only defined through types while there is no code for the
actual function logic that can be analyzed. This makes it impossible
to tell whether the given call expression actually causes the specified
arrow function to be executed synchronously or not. In order to be able
to make this better, we now peek into the passed arrow function and
check for a synchronous query usage. If so, we set the query timing to
static and mark it as ambiguous. This ensures that the usage strategy is
less "magical" and more correct with third-party code.

Additionally since functions like `setTimeout` are not analyzable but known
to be asynchronous, there is a hard-coded list of known functions which
shouldn't be marked as ambiguous.

Resolves FW-1214. As planned within https://hackmd.io/hPiLWpPlQ4uynC1luIBdfQ

PR Close #30215
2019-05-09 14:39:06 -07:00
10b43355f8 test(core): update core_all size-tracking golden file (#30257)
Even though we don't run the size-tracking test on CI
right now, we update the golden size map as part of
the size-tracking tool update. The size-map difference
should generally be kept up-to-date to be able to
determine which PRs contribute size to a given file.

PR Close #30257
2019-05-09 12:55:17 -07:00
d4e7587bd8 build: size-tracking test should support max-byte threshold (#30257)
Based on discussion that happened on the PR that introduced
the size-tracking tool, we want to have another threshold for
the raw byte difference. This allows us to better control for
which changes the size-tracking tool should report a difference.

See: https://github.com/angular/angular/pull/30070#discussion_r278332315

PR Close #30257
2019-05-09 12:55:17 -07:00
cabe03cf6d docs(forms): properly convert number to string for formControlName input (#29473)
PR Close #29473
2019-05-09 11:27:49 -07:00
0cefa9e342 docs: fix filename in example headers for provider guides (#29889)
PR Close #29889
2019-05-09 11:27:01 -07:00
e073daa48e docs(forms): add comment of the value (#29898)
PR Close #29898
2019-05-09 11:25:58 -07:00
994d48a96e test(ivy): update devkit in hello world tests to rc.2 (#30162)
PR Close #30162
2019-05-09 11:24:52 -07:00
806f8118c8 docs: remove reference to e2e applications (#30324)
This is no longer applicable in angular version 8.

PR Close #30324
2019-05-09 11:23:06 -07:00
dd299f9eb2 fix(core): static-query migration should handle queries on accessors (#30327)
Currently the static-query migration ignores queries declared on getters
or setters as these are not part of a `PropertyDeclaration`. We need to
handle these queries in order to cover all queries within a given project.

The usage strategy is not able to detect timing for queries on accessors,
so we add a TODO and print a message. The template strategy is able
to detect the proper timing for such queries because it's not dependent
on detecting the usage of the query.

Resolves FW-1215

PR Close #30327
2019-05-09 11:22:37 -07:00
49ec3f312c fix(docs-infra): Handle search criteria from Chrome search providers (#30345)
fixes #30242

PR Close #30345
2019-05-09 11:21:12 -07:00
71eba450e6 fix(bazel): pass correct arguments to http_server in Windows (#30346)
Under Windows, the server binary has an extension of  `.exe` and the current logic is not handling that.

Partially addresses: #29785

PR Close #30346
2019-05-09 11:20:52 -07:00
192f108b0f fix: ensure strict mode when evaluating in JIT (#30122)
PR Close #30122
2019-05-08 14:34:10 -07:00
dd8651db73 fix(core): CSS sanitizer now allows parens in file names (#30322)
Resolves an issue where images that were created with a name like `'foo (1).png'` would not pass CSS url sanitization.

PR Close #30322
2019-05-08 14:22:44 -07:00
5bbbe3f684 docs(router): Move ActivatedRoute example to mini-app (#29755)
PR Close #29755
2019-05-08 13:52:23 -07:00
a71d8a837b fix(core): static-query migration should gracefully exit if AOT compiler throws (#30269)
The static-query template strategy leverages the AOT compiler
in order to determine the query timing. Unfortunately the AOT
compiler has open bugs that can cause unexpected failures which
make the template strategy unusable in rare cases. These rare
exceptions need to be handled gracefully in order to avoid confusion
and to provide a more smooth migration.

Additionally migration strategy setup failures are now reported with
stack traces as the `ng update` command does not print stack traces.
This makes it easier to reproduce and report migration issues.

PR Close #30269
2019-05-08 11:54:34 -07:00
e8ceae14e1 fix(core): migrations not always migrating all files (#30269)
In an Angular CLI project scenario where projects only reference
top-level source-files through the `tsconfig` `files` option, we currently
do not migrate referenced source-files. This can be fixed checking all
referenced source-files which aren't coming from an external library.

This is similar to how `tslint` determines project source-files.

PR Close #30269
2019-05-08 11:54:34 -07:00
c3246e6f16 fix(core): static-query migration fails with default parameter values (#30269)
Currently when someone has a call expression within the `ngOnInit` call
and we try to peek into that function with respect to the current function
context, the schematic errors because a call expression argument is
undefined. This is valid because the target function declaration defines
that parameter with a default value. In order to fix this, we need to
respect parameter default values.

PR Close #30269
2019-05-08 11:54:34 -07:00
685753361e fix(docs-infra): remove scroll position from sessionStorage when a ServiceWorker update has been activated (#29958)
closes #29893

PR Close #29958
2019-05-08 09:23:43 -07:00
6b07711f96 test(core): run schematic tests with public migration collection (#30198)
572b54967c changed how the schematic
tests are executed. Tests no longer use the schematic collection
that is also used by the CLI `ng update` command and therefore
the migration collection could  technically be invalid.

In order to ensure that the public migration collection is guaranteed
to work and to avoid duplication within two schematic collections, the
changes are partially reverted and only the disabled `injectable-pipe`
schematic has its own collection.

PR Close #30198
2019-05-08 09:23:29 -07:00
12fb639b7d fix(core): static-query migration should not prompt if no queries are used (#30254)
Currently we always prompt when the static-query migration runs. This is not
always needed because some applications do not even use `ViewChild` or
`ContentChild` queries and it just causes confusion if developers need to
decide on a migration strategy while there is nothing to migrate.

In order to avoid this confusion, we no longer prompt for a strategy
if there are no queries declared within the project.

PR Close #30254
2019-05-08 09:22:49 -07:00
644925fd0c build: add jasonaden to angular/upgrade in CODEOWNERS (#30307)
PR Close #30307
2019-05-08 09:20:25 -07:00
bcc72b0924 test(ivy): move host binding tests to acceptance (#30308)
Switches over all host binding tests to use `TestBed` and to be under `acceptance`.

PR Close #30308
2019-05-08 09:19:44 -07:00
e1091b2ba8 build(docs-infra): upgrade cli command docs sources to cd7920355 (#30326)
Updating [angular#8.0.x](https://github.com/angular/angular/tree/8.0.x) from [cli-builds#8.0.x](https://github.com/angular/cli-builds/tree/8.0.x).

##
Relevant changes in [commit range](73c53266f...cd7920355):

**Modified**
- help/e2e.json
- help/generate.json
- help/update.json

##

PR Close #30326
2019-05-08 09:15:22 -07:00
08841e31d9 Revert "fix(router): fix a problem with router not responding to back button (#30160)" (#30320)
This reverts commit 3327bd8eab.

PR Close #30320
2019-05-07 17:22:25 -07:00
d1fcc2bc13 fix(bazel): Directly spawn native Bazel binary (#30306)
Instead of launching a Node.js process that in turn spawns Bazel binary,
the Builder could now directly spawn the native binary. This makes the
bootup process slightly more efficient, and allows the Builder to
control spawn options. This works with both Bazel and iBazel.

PR Close #30306
2019-05-07 16:51:42 -07:00
fac00442d2 fix(core): consistently use ng:/// for sourcemap URLs (#29826)
Currently, in jit mode, `ngInjectableDef`, `ngDirectiveDef`, `ngPipeDef` and `ngModuleDef` use `ng://`,
which display them in the top domain in Chrome Dev Tools, whereas `ngComponentDef` uses `ng:///` which display components in a separate domain.

You can currently see:

```
AppModule
UserService
ng://
|_ AppComponent
   |_ template.html
|_ AppComponent.js
...
```

This commits replaces all `ng://` with `ng:///` to display every Angular entity in the `ng://` domain.

```
ng://
|_ AppModule
|_ UserService
|_ AppComponent
...
```

PR Close #29826
2019-05-07 15:37:21 -07:00
b8cbcbcf49 release: cut the v8.0.0-rc.3 release 2019-05-07 14:30:37 -07:00
1ed45bd783 docs(aio): add awade jigsaw into resources (#30204)
PR Close #30204
2019-05-07 13:13:22 -07:00
82fd1920b1 docs: update date pipe example for minutes and seconds (#30281) (#30295)
PR Close #30295
2019-05-07 10:29:31 -07:00
f6d7271ec7 refactor: remove tslint no-use-before-declare rule (#30288)
PR Close #30288
2019-05-07 10:25:36 -07:00
c1f3faf1df test: fix several bazel compiler-cli tests in windows (#30189)
```
//packages/compiler-cli/integrationtest:integrationtest
//packages/compiler-cli/test/compliance:compliance
```

Partially addresses #29785

PR Close #30189
2019-05-07 10:21:37 -07:00
97202278f9 fix(router): ensure history.state is set in eager update mode (#30154)
Without this change, `history.state` isn't being set when updating the browser URL in `eager` update mode.

PR Close #30154
2019-05-06 16:09:59 -07:00
132f01c5ca fix(router): fix a problem with router not responding to back button (#30160)
There was a problem with a combination of the `eager` URL update, browser `back` button, and hybrid applications. Details provided in internal ticket http://b/123667227.

This fix handles the problem by setting `router.browserUrlTree` when all conditions have failed, meaning the browser doesn't do anything with the navigation other than update internal data structures. Without this change, the problem was an old value was stored in `router.broserUrlTree` causing some new navigations to be compared to an old value and breaking future navigations.

PR Close #30160
2019-05-06 16:06:59 -07:00
6a987f1b9c docs(forms): fix import line ending (#30290)
PR Close #30290
2019-05-06 16:05:23 -07:00
548b003ed3 fix(compiler-cli): log ngcc skipping messages as debug instead of info (#30232)
Related to https://github.com/angular/angular-cli/issues/14194, https://github.com/angular/angular-cli/pull/14320

PR Close #30232
2019-05-06 14:11:28 -07:00
48dc41de01 docs: fix naming miss and improve anchor reference in router guide (#30225)
Signed-off-by: Richard Lea <chigix@zoho.com>

PR Close #30225
2019-05-06 11:48:05 -07:00
817c2b49bc docs: add explanation on what lazy loading is (#29667)
PR Close #29667
2019-05-06 10:16:58 -07:00
fed07c735c docs(forms): fix ControlValueAccessor registerOnChange code example (#30276)
PR Close #30276
2019-05-06 09:27:12 -07:00
390cac6874 docs: fix targetEntryPointPath description (#30237)
PR Close #30237
2019-05-06 09:21:23 -07:00
8eb0b8bd40 docs: update Wikipedia link to Polyfill description (#30214)
PR Close #30214
2019-05-06 09:20:14 -07:00
d7283c6085 docs: fix example header in singleton services guide to match styleguide (#30097)
Removes the ".0" from code header, as that doesn't match the
recommended code style for service files names.

fixes #29862

PR Close #30097
2019-05-06 09:19:36 -07:00
3fe3a84a4b fix(core): fix interpolate identifier in AOT (#30243)
This commit fixes a regression introduced in PR 29692 where
the interpolate symbol in View Engine was improperly prefixed
with the ɵɵ that signifies private instructions for Ivy. It
resulted in interpolations of 10+ values not working correctly
in AOT mode. This commit removes the prefix.

PR Close #30243
2019-05-02 10:33:34 -07:00
28e4187bd6 fix(docs-infra): update app code to work with Ivy (#28530)
This commit also enables more tests to be run on CI with Ivy.

PR Close #28530
2019-05-01 16:38:33 -07:00
7cbc69c890 fix(ivy): allow R3TestBedCompiler to work in ngcc-processed apps (#28530)
Previously, `R3TestBedCompiler` was dynamically defining an
`@NgModule`-decorated `CompilerModule` class inside a method call.
Since ngcc only processes top-level classes, this class was not
transformed causing failures in unit tests (see #30121 for details).

This commit fixes it by using `compileNgModuleDefs()` directly (similar
to the fix in #30037).

Fixes #30121

PR Close #28530
2019-05-01 16:38:33 -07:00
1dc134bc6b docs: explicitly state purpose of components (#29879)
Current description is vague. I'd love to see this doc explicitly state that components are for reusable sets of UI features instead.

PR Close #29879
2019-05-01 13:38:13 -07:00
6a61d37f95 ci(docs-infra): re-enable aio_monitoring CircleCI jobs and change time (#30168)
The `aio_monitoring_next` CircleCI job was disabled due to a failure in
[302254](https://circleci.com/gh/angular/angular/302254). It turned out
the failure was caused because the job happened to run after a change
had been merged into master and right before it was deployed to
https://next.angular.io/ causing the tests not to match the deployed
version.

This commit re-enables the job and moves it to a different time, when it
is less likely that PRs will be being merged (and thus reducing the risk
of a similar timming issue).

Fixes #30101

PR Close #30168
2019-04-30 16:17:53 -07:00
8d2e92bcfe build(docs-infra): upgrade material and cdk to 8.0.0-rc.0 (#30202)
I bumped the payload size limits to reflect the current values - the changes have been insignificant.

PR Close #30202
2019-04-29 18:46:54 -07:00
5038f5c909 build(docs-infra): upgrade framework and cli to 8.0.0-rc.2 (#30202)
Brings in small payload size fixes.

PR Close #30202
2019-04-29 18:46:54 -07:00
6eeca70043 refactor(core): static-query migrations fails if options cannot be transformed (#30178)
Currently the `static-query` migrations fails at the final step of
updating a query when the query already specifies options which
cannot be transformed easily. e.g. the options are computed through
a function call: `@ViewChild(..., getQueryOpts());` or `@ViewChild(..., myOptionsVar)`.

In these cases we technically could add additionally logic to update
the query options, but given that this is an edge-case and it's
potentially over-engineering the migration schematic, we just
always add a TODO for the timing and print out the determined
query timing in the console. The developer in that case just needs
to manually update the logic for the query options to contain the
printed query timing.

Potentially related to: https://github.com/angular/angular-cli/issues/14298

PR Close #30178
2019-04-29 13:30:37 -07:00
9f68c35fa9 fix(bazel): Bump ibazel to 0.10.1 for windows fixes (#30196)
PR Close #30196
2019-04-29 13:29:12 -07:00
21418ea109 test: fix ngc-wrapped bazel tests in windows (#30111)
Partially addresses #29785

PR Close #30111
2019-04-29 13:23:45 -07:00
02d8b4ed3c docs: add in-page nav, change title to match left nav better (#30093)
PR Close #30093
2019-04-29 13:23:15 -07:00
6748392edc docs: add architect terms (#26963)
PR Close #26963
2019-04-29 13:22:20 -07:00
d9fd301157 build(docs-infra): update the aio app to framework and cli 8.0.0-rc.1 (#30183)
I updated the payload size limits as well. There still seem to be size regressions in the framework,
but at least the polyfills now uses the evergreen build of zones so we shaved off a few KB there.

PR Close #30183
2019-04-29 12:30:26 -07:00
71c5d80ce7 build: add size-tracking bazel test (#30070)
Introduces a new Bazel test that allows us to inspect
what source-files contribute to a given bundled file
and how much bytes they contribute to the bundle size.

Additionally the size-tracking rule groups the size
data by directories. This allows us to compare size
changes in the scope of directories. e.g. a lot of
files in a directory could increase slightly in size, but
in the directory scope the size change could be significant
and needs to be reported by the test target.

Resolves FW-1278

PR Close #30070
2019-04-29 12:29:25 -07:00
9798229fde release: cut the v8.0.0-rc.2 release 2019-04-29 12:03:39 -07:00
4b2fcfd5dc fix: disable injectable-pipe migration (#30180)
Disables the injectable pipe migration until we can decide whether this is the right solution for Ivy. Rolling it out properly will involve a more detailed plan and more changes like updating the styleguide, scaffolding schematics etc.

Context for the new `test-migrations.json`: since we use the `migrations.json` both for the real migrations and for tests, it doesn't allow us to disable a schematic, but continue running its tests. This change adds the test-specific file so that we can continue running the `injectable-pipe` tests, even though the schematic itself is disabled.

PR Close #30180
2019-04-29 09:40:00 -07:00
b4d291aa7a fix(ivy): injectable pipe schematic generating incorrect import statements (#30170)
Currently the injectable pipe schematic generates invalid imports like `import import { Pipe, PipeTransform, Injectable } from '@angular/core'; from '@angular/core';`. The issue wasn't caught by the unit tests, because the invalid import still contains the valid one.

Fixes #30159.

PR Close #30170
2019-04-29 09:39:11 -07:00
b0ecafdc2f docs: temporary disable aio_monitoring job due to a version skew (#30161)
It looks like `aio_monitoring` CircleCI job is still failing. Disabling it for now to keep master green.

PR Close #30161
2019-04-26 17:38:59 -07:00
6816bb62d7 Revert "refactor: use new Http library in playground (#29355)"
This reverts commit 908d43a5bb.
2019-04-26 16:51:38 -07:00
4b05b8cea0 refactor(ivy): move exports tests to acceptance (#30157)
PR Close #30157
2019-04-26 16:37:34 -07:00
a0728aedf7 docs: update readme. sentence correction. (#30136)
PR Close #30136
2019-04-26 16:36:53 -07:00
ea96f6112a build: unable to accept new symbol-extractor golden on windows (#30127)
Currently when working on Windows, it's not possible to accept a new
golden for a `symbol-extractor` Bazel test. This is because the generated
executable output from the `nodejs_binary` rule (without a macro) misses
a Windows executable wrapper that sets up the proper environment
variables for the runfiles. Causing the following failure on Windows:

```
 >>>> FAIL: RUNFILES environment variable is not set. <<<<
```

PR Close #30127
2019-04-26 16:35:51 -07:00
b706800ea8 fix(language-service): Remove tsserverlibrary from rollup globals (#30123)
This PR removes `tsserverlibrary` from rollup globals since the symbol
should not appear by the time rollup is invoked. `tsserverlibrary` is
used for types only, so the import statement should not be emitted by
tsc.

PR Close #30123
2019-04-26 16:35:05 -07:00
c6f95b1d70 ci: enable language service tests in codefresh (#30113)
PR Close #30113
2019-04-26 16:34:23 -07:00
d896126604 test: fix language service tests in windows (#30113)
This PR parially addresses #29785 and fixes ` //packages/language-service/test:test`

PR Close #30113
2019-04-26 16:34:23 -07:00
a20da5ddcc ci(docs-infra): use the tests from the stable branch in aio_monitoring_stable CircleCI job (#30110)
Previously, the `aio_monitoring_stable` job (which runs tests against
https://angular.io/) was using the tests from the master branch. As a
result, if the master branch included changes in those tests that were
not yet backported to the stable branch (and thus deployed to
https://angular.io/), the tests would fail.

This commit fixes this by using the tests from the stable branch to test
against https://angular.io/.

Fixes #30101

PR Close #30110
2019-04-26 16:33:46 -07:00
18878600ba ci(docs-infra): split the aio_monitoring CircleCI job into two jobs (#30110)
Previously, the `aio_monitoring` job was testing both the stable
(https://angular.io/) and the @next (https://next.angular.io/) versions.

This commit splits the tests into two separate jobs (still run as part
of the same workflow). This speeds up the tests (since the two jobs can
now run in parallel) and makes it easier to isolate failures (e.g.
identify which branch is failing, disable one of the two, etc.).
(Credits to @petebacondarwin 😉)

PR Close #30110
2019-04-26 16:33:46 -07:00
d7e10f3f7e ci(docs-infra): re-use setup CircleCI job in aio_monitoring (#30110)
PR Close #30110
2019-04-26 16:33:46 -07:00
4d044ea5b2 ci(docs-infra): re-enable aio_monitoring CircleCI job (#30110)
The job started failing for https://angular.io/, due to changes in tests
that only affected https://next.angular.io/, and was disabled in #30102.

This commit re-enables the job (since it does not block anything and it
will be fixed in a subsequent commit).

PR Close #30110
2019-04-26 16:33:46 -07:00
e2d1e0cd98 docs(docs-infra): fix typo in workspace-config.md file (#30108)
Fixed typo in 'Project asset configuration' section inside workdspace-config.md

PR Close #30108
2019-04-26 16:33:03 -07:00
4e056580bb test: fix api guardian tests on windows when node_modules are not installed (#30105)
When the workspace node_modules are not installed outside of bazel context the api guardian tests fails because the tree artifacts files are not symlinked in windows.

We need to pass the node module location in the node_path

PR Close #30105
2019-04-26 16:32:23 -07:00
e4c2e6a904 ci: add public_api_guard tests to codefresh config (#30105)
PR Close #30105
2019-04-26 16:32:23 -07:00
a50989832d test: fix ts api guardian and public guard tests on windows (#30105)
This change addresses several issues with ts-api-guardian and public api guards related tests in Windows

The fixes contain 3 main changes:
1) In `stripExportPattern` - replace `^` with `^^^^`  in RegExp due to a double escaping requirment under Windows. Note that under Linux this the extra character has no effect because it's still a valid RegExp in Js.

2. Force `*.patch` files to always be with a LF line sequence instead of CRLF in windows

3. When adding JSDoc comments consider the presence of a carriage return in a line new feed

Partially addresses #29785

PR Close #30105
2019-04-26 16:32:23 -07:00
525307b6a3 fix(ivy): correctly reflect undefined values (#30103)
Fixes Ivy reflecting properties with `undefined` values, rather than omitting them. Also fixes that Ivy doesn't clear the reflected values when property value changes from something that is defined to undefined.

This PR resolves FW-1277.

PR Close #30103
2019-04-26 16:31:50 -07:00
a3ab76b216 docs: update redirect links and fix typo (#30092)
PR Close #30092
2019-04-26 16:31:04 -07:00
f2265d4b46 build: upgrade yargs package to 13.1.0 (#29722)
Update yargs, because the old version was transitively (via os-local) depending on a vulnerable version of the mem package: https://app.snyk.io/vuln/npm:mem:20180117

PR Close #29722
2019-04-26 16:29:29 -07:00
d3ac709b99 fix(ivy): @Component should support entry components from another module (#29566)
PR Close #29566
2019-04-26 16:27:19 -07:00
908d43a5bb refactor: use new Http library in playground (#29355)
PR Close #29355
2019-04-26 16:26:31 -07:00
71cdb0a08e refactor(ivy): move di tests for inject to acceptance (#29299)
PR Close #29299
2019-04-26 16:23:44 -07:00
c7fbbdfa99 refactor(ivy): move di tests for flags to acceptance (#29299)
Including tests for `@Optional`, `@Self`, `@SkipSelf` and `@Host`.

PR Close #29299
2019-04-26 16:23:44 -07:00
10e4ab7712 refactor(ivy): move di tests for directive injection to acceptance (#29299)
PR Close #29299
2019-04-26 16:23:44 -07:00
5114c23c21 refactor(ivy): move di tests for DI tokens to acceptance (#29299)
Move tests for special tokens like `Injector`, `ElementRef`, `TemplateRef`, `ViewContainerRef`, `ChangeDectetorRef` and custom string tokens.

PR Close #29299
2019-04-26 16:23:43 -07:00
c3e585d7eb refactor(ivy): move di tests for Attribute to acceptance (#29299)
PR Close #29299
2019-04-26 16:23:43 -07:00
0776daec88 release: cut the v8.0.0-rc.1 release 2019-04-26 13:28:49 -07:00
615e1a58b2 test(ivy): pin deps on hello world size tests (#30152)
We recently had an unexpected size regression in the hello world
tests because the CLI devkit released an RC that regressed us and
the dependencies were not pinned. This change ensures that we only
update dependencies like devkit deliberately, so we do not have
mysterious breakages caused by other packages.

PR Close #30152
2019-04-26 12:34:10 -07:00
606758357e fix(bazel): update peerDep ranges (#30155)
PR Close #30155
2019-04-26 12:32:35 -07:00
ba2a3595c6 fix(ivy): output should not be subscribe twice when 2 listeners (#30144)
PR Close #30144
2019-04-26 11:11:09 -07:00
a50bfe5054 fix(ivy): property bindings use correct indices (#30129)
- Extracts and documents code that will be common to interpolation instructions
- Ensures that binding indices are updated at the proper time during compilation
- Adds additional tests

Related #30011

PR Close #30129
2019-04-26 11:09:51 -07:00
c8983bc367 docs: remove note about ivy being coupled to dynamic import (#30151)
PR Close #30151
2019-04-26 11:08:51 -07:00
8d6d2c6704 build: bazel ts-api-guardian usage fails on workspaces which don't depend on chalk (#30138)
When using the npm package in a workspace which doesn't depend on chalk, ts-api-guardian fails with an error `Error: Cannot find module 'chalk'`

PR Close #30138
2019-04-26 11:08:05 -07:00
6711f22e62 fix(bazel): Exclude common/upgrade* in metadata.tsconfig.json (#30133)
It has a dependency on @angular/upgrade which is not part of the
dependencies in package.json, so postinstall would fail.

PR Close #30133
2019-04-26 11:07:34 -07:00
8dd9192fe3 refactor(ivy): undeprecate inject (#30132)
PR Close #30132
2019-04-26 11:06:42 -07:00
870e0dab48 fix(ivy): remove debug utilities from ivy production builds (#30130)
Prior to this commit, we were pulling DebugNode and DebugElement
into production builds because BrowserModule automatically pulled
in NgProbe and thus getDebugNode. In Ivy, this is not necessary
because Ivy has its own set of debug utilities. We should use these
existing tools instead of NgProbe.

This commit adds an Ivy switch so we do not pull in NgProbe utilities
when running with Ivy. This saves us ~8KB in prod builds.

PR Close #30130
2019-04-26 11:04:48 -07:00
1114 changed files with 36337 additions and 92011 deletions

View File

@ -1,4 +1,3 @@
.git
node_modules node_modules
dist dist
aio/content aio/content

View File

@ -1,3 +1,14 @@
###############################
# Typescript / Angular / Sass #
###############################
# Make compilation fast, by keeping a few copies of the compilers
# running as daemons, and cache SourceFile AST's to reduce parse time.
build --strategy=AngularTemplateCompile=worker
# TODO(alexeagle): re-enable after fixing worker instability with rxjs typings
# build --strategy=TypeScriptCompile=worker
build --strategy=TypeScriptCompile=standalone
# Enable debugging tests with --config=debug # Enable debugging tests with --config=debug
test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results
@ -74,6 +85,12 @@ query --output=label_kind
# By default, failing tests don't print any output, it goes to the log file # By default, failing tests don't print any output, it goes to the log file
test --test_output=errors test --test_output=errors
# Show which actions are run under workers,
# and print all the actions running in parallel.
# Helps to demonstrate that bazel uses all the cores on the machine.
build --experimental_ui
test --experimental_ui
################################ ################################
# Settings for CircleCI # # Settings for CircleCI #
################################ ################################
@ -137,31 +154,6 @@ build:remote --bes_results_url="https://source.cloud.google.com/results/invocati
# This allows us to avoid installing a second copy of node_modules # This allows us to avoid installing a second copy of node_modules
common --experimental_allow_incremental_repository_updates common --experimental_allow_incremental_repository_updates
# This option is changed to true in Bazel 0.27 and exposes a possible
# regression in Bazel 0.27.0.
# Error observed is in npm_package target `//packages/common/locales:package`:
# ```
# ERROR: /home/circleci/ng/packages/common/locales/BUILD.bazel:13:1: Assembling
# npm package packages/common/locales/package failed: No usable spawn strategy found
# for spawn with mnemonic SkylarkAction. Your --spawn_strategyor --strategy flags
# are probably too strict. Visit https://github.com/bazelbuild/bazel/issues/7480 for
# migration advises
# ```
# Suspect is https://github.com/bazelbuild/rules_nodejs/blob/master/internal/npm_package/npm_package.bzl#L75-L82:
# ```
# execution_requirements = {
# # Never schedule this action remotely because it's not computationally expensive.
# # It just copies files into a directory; it's not worth copying inputs and outputs to a remote worker.
# # Also don't run it in a sandbox, because it resolves an absolute path to the bazel-out directory
# # allowing the .pack and .publish runnables to work with no symlink_prefix
# # See https://github.com/bazelbuild/rules_nodejs/issues/187
# "local": "1",
# },
# ```
build --incompatible_list_based_execution_strategy_selection=false
test --incompatible_list_based_execution_strategy_selection=false
run --incompatible_list_based_execution_strategy_selection=false
#################################################### ####################################################
# User bazel configuration # User bazel configuration
# NOTE: This needs to be the *last* entry in the config. # NOTE: This needs to be the *last* entry in the config.

42
.buildkite/Dockerfile Normal file
View File

@ -0,0 +1,42 @@
# Heavily based on https://github.com/StefanScherer/dockerfiles-windows/ images.
# Combines the node windowsservercore image with the Bazel Prerequisites (https://docs.bazel.build/versions/master/install-windows.html).
# msys install taken from https://github.com/StefanScherer/dockerfiles-windows/issues/30
# VS redist install taken from https://github.com/StefanScherer/dockerfiles-windows/blob/master/apache/Dockerfile
# The nanoserver image won't work because MSYS2 does not run in it https://github.com/Alexpux/MSYS2-packages/issues/1493
# Before building this image, you must locally build node-windows:10.13.0-windowsservercore-1803.
# Clone https://github.com/StefanScherer/dockerfiles-windows/commit/4ce7101a766b9b880ac262479dd9126b64d656cf and build using
# docker build -t node-windows:10.13.0-windowsservercore-1803 --build-arg core=microsoft/windowsservercore:1803 --build-arg target=microsoft/windowsservercore:1803 .
FROM node-windows:10.13.0-windowsservercore-1803
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
# Install 7zip to extract msys2
RUN Invoke-WebRequest -UseBasicParsing 'https://www.7-zip.org/a/7z1805-x64.exe' -OutFile 7z.exe
# For some reason the last letter in the destination directory is lost. So '/D=C:\\7zip0' will extract to '/D=C:\\7zip'.
RUN Start-Process -FilePath 'C:\\7z.exe' -ArgumentList '/S', '/D=C:\\7zip0' -NoNewWindow -Wait
# Extract msys2
RUN Invoke-WebRequest -UseBasicParsing 'http://repo.msys2.org/distrib/x86_64/msys2-base-x86_64-20180531.tar.xz' -OutFile msys2.tar.xz
RUN Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'e', 'msys2.tar.xz' -Wait
RUN Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'x', 'msys2.tar', '-oC:\\' -Wait
RUN Remove-Item msys2.tar.xz
RUN Remove-Item msys2.tar
RUN Remove-Item 7z.exe
RUN Remove-Item -Recurse 7zip
# Add MSYS2 to PATH, and set BAZEL_SH
RUN [Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\msys64\usr\bin', [System.EnvironmentVariableTarget]::Machine)
RUN [Environment]::SetEnvironmentVariable('BAZEL_SH', 'C:\msys64\usr\bin\bash.exe', [System.EnvironmentVariableTarget]::Machine)
# Install Microsoft Visual C++ Redistributable for Visual Studio 2015
RUN Invoke-WebRequest -UseBasicParsing 'https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x64.exe' -OutFile vc_redist.x64.exe
RUN Start-Process 'c:\\vc_redist.x64.exe' -ArgumentList '/Install', '/Passive', '/NoRestart' -NoNewWindow -Wait
RUN Remove-Item vc_redist.x64.exe
# Add a fix for https://github.com/docker/for-win/issues/2920 as entry point to the container.
SHELL ["cmd", "/c"]
COPY "fix-msys64.cmd" "C:\\fix-msys64.cmd"
ENTRYPOINT cmd /C C:\\fix-msys64.cmd && cmd /c
CMD ["cmd.exe"]

96
.buildkite/README.md Normal file
View File

@ -0,0 +1,96 @@
# BuildKite configuration
This folder contains configuration for the [BuildKite](https://buildkite.com) based CI checks for
this repository.
BuildKite is a CI provider that provides build coordination and reports while we provide the
infrastructure.
CI runs are triggered by new PRs and will show up on the GitHub checks interface, along with the
other current CI solutions.
Currently it is only used for tests on Windows platforms.
## The build pipeline
BuildKite uses a pipeline for each repository. The `pipeline.yml` file defines pipeline
[build steps](https://buildkite.com/docs/pipelines/defining-steps) for this repository.
Run results can be seen in the GitHub checks interface and in the
[pipeline dashboard](https://buildkite.com/angular/angular).
Although most configuration is done via `pipeline.yml`, some options are only available
in the online [pipeline settings](https://buildkite.com/angular/angular/settings).
## Infrastructure
BuildKite does not provide the host machines where the builds runs, providing instead the
[BuildKite Agent](https://buildkite.com/docs/agent/v3) that should be run our own infrastructure.
### Agents
This agent polls the BuildKite API for builds, runs them, and reports back the results.
Agents are the unit of concurrency: each agent can run one build at any given time.
Adding agents allows more builds to be ran at the same time.
Individual agents can have tags, and pipeline steps can target only agents with certain tags via the
`agents` field in `pipeline.yml`.
For example: agents on Windows machines are tagged as `windows`, and the Windows specific build
steps list `windows: true` in their `agents` field.
You can see the current agent pool, along with their tags, in the
[agents list](https://buildkite.com/organizations/angular/agents).
### Our host machines
We use [Google Cloud](https://cloud.google.com/) as our cloud provider, under the
[Angular project](https://console.cloud.google.com/home/dashboard?project=internal-200822).
To access this project you need need to be logged in with a Google account that's a member of
team@angular.io.
For googlers this may be your google.com account, for others it is an angular.io account.
In this project we have a number of Windows VMs running, each of them with several agents.
The `provision-windows-buildkite.ps1` file contains instructions on how to create new host VMs that
are fully configured to run the BuildKite agents as services.
Our pipeline uses [docker-buildkite-plugin](https://github.com/buildkite-plugins/docker-buildkite-plugin)
to run build steps inside docker containers.
This way we achieve isolation and hermeticity.
The `Dockerfile` file describes a custom Docker image that includes NodeJs, Yarn, and the Bazel
pre-requisites on Windows.
To upload a new version of the docker image, follow any build instructions in `Dockerfile` and then
run `docker build -t angular/node-bazel-windows:NEW_VERSION`, followed by
`docker push angular/node-bazel-windows:NEW_VERSION`.
After being pushed it should be available online, and you can use the new version in `pipeline.yml`.
## Caretaker
BuildKite status can be found at https://www.buildkitestatus.com/.
Issues related to the BuildKite setup should be escalated to the Tools Team via the current
caretaker, followed by Alex Eagle and Filipe Silva.
Support requests should be submitted via email to support@buildkite.com and cc Igor, Misko, Alex,
Jeremy and Manu
## Rollout strategy
At the moment our BuildKite CI uses 1 host VM running 4 agents, thus being capable of 4 concurrent
builds.
The only test running is `bazel test //tools/ts-api-guardian:all`, and the PR check is not
mandatory.
In the future we should add cache support to speed up the initial `yarn` install, and also Bazel
remote caching to speed up Bazel builds.
After the current setup is verified as stable and reliable the GitHub PR check can become mandatory.
The tests ran should also be expanded to cover most, if not all, of the Bazel tests.

View File

@ -0,0 +1,6 @@
@echo off
REM Fix for https://github.com/docker/for-win/issues/2920
REM echo "Fixing msys64 folder..."
REM Touch all .dll files inside C:\msys64\
forfiles /p C:\msys64\ /s /m *.dll /c "cmd /c Copy /B @path+,, >NUL"
REM echo "Fixed msys64 folder."

10
.buildkite/pipeline.yml Normal file
View File

@ -0,0 +1,10 @@
steps:
- label: windows-test
commands:
- "yarn install --frozen-lockfile --non-interactive --network-timeout 100000"
- "yarn bazel test //tools/ts-api-guardian:all --noshow_progress"
plugins:
- docker#v2.1.0:
image: "filipesilva/node-bazel-windows:0.0.2"
agents:
windows: true

View File

@ -0,0 +1,94 @@
# PowerShell script to provision a Windows Server with BuildKite
# This script follows https://buildkite.com/docs/agent/v3/windows.
# Instructions
# VM creation:
# In Google Cloud Platform, create a Compute Engine instance.
# We recommend machine type n1-standard-16 (16 vCPUs, 60 GB memory).
# Use a recent windows boot disk with container support such as
# "Windows Server version 1803 Datacenter Core for Containers", and add a 128GB SSD disk.
# Give it a name, then click "Create".
# VM setup:
# In the Compute Engine menu, select "VM Instances". Click on the VM name you chose before.
# Click "Set Windows Password" to choose a username and password.
# Click RDP to open a remote desktop via browser, using the username and password.
# In the Windows command prompt start an elevated powershell by inputing
# "powershell -Command "Start-Process PowerShell -Verb RunAs" followed by Enter.
# Download and execute this script from GitHub, passing the token (mandatory), tags (optional)
# and number of agents (optional) as args:
# ```
# Invoke-WebRequest -Uri https://raw.githubusercontent.com/angular/angular/master/.buildkite/provision-windows-buildkite.ps1 -OutFile provision.ps1
# .\provision.ps1 -token "MY_TOKEN" -tags "windows=true,another_tag=true" -agents 4
# ```
# The VM should restart and be fully configured.
# Creating extra VMs
# You can create an image of the current VM by following the instructions below.
# https://cloud.google.com/compute/docs/instances/windows/creating-windows-os-image
# Then create a new VM and choose "Custom images".
# Script proper.
# Get the token and tags from arguments.
param (
[Parameter(Mandatory=$true)][string]$token,
[string]$tags = "",
[Int]$agents = 1
)
# Allow HTTPS
[Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
# Helper to add to PATH.
# Will take current PATH so avoid running it after anything to modifies only the powershell session path.
function Add-Path ([string]$newPathItem) {
$Env:Path+= ";" + $newPathItem + ";"
[Environment]::SetEnvironmentVariable("Path",$env:Path, [System.EnvironmentVariableTarget]::Machine)
}
# Install Git for Windows
Write-Host "Installing Git for Windows."
Invoke-WebRequest -Uri https://github.com/git-for-windows/git/releases/download/v2.19.1.windows.1/Git-2.19.1-64-bit.exe -OutFile git.exe
.\git.exe /VERYSILENT /NORESTART /NOCANCEL /SP- /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /COMPONENTS="icons,ext\reg\shellhere,assoc,assoc_sh" /DIR="C:\git"
Add-Path "C:\git\bin"
# Sleep for 15s while git is installed. Trying to remove the git.exe before it finishes install causes an error.
Start-Sleep -s 15
Remove-Item git.exe
# Download NSSM (https://nssm.cc/) to run the BuildKite agent as a service.
Write-Host "Downloading NSSM."
Invoke-WebRequest -Uri https://nssm.cc/ci/nssm-2.24-101-g897c7ad.zip -OutFile nssm.zip
Expand-Archive -Path nssm.zip -DestinationPath C:\nssm
Add-Path "C:\nssm\nssm-2.24-101-g897c7ad\win64"
Remove-Item nssm.zip
# Run the BuildKite agent install script
Write-Host "Installing BuildKite agent."
$env:buildkiteAgentToken = $token
$env:buildkiteAgentTags = $tags
Set-ExecutionPolicy Bypass -Scope Process -Force
iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/buildkite/agent/master/install.ps1'))
# Configure the BuildKite agent clone and timestamp behavior
Add-Content C:\buildkite-agent\buildkite-agent.cfg "`ngit-clone-flags=--config core.autocrlf=input --config core.eol=lf --config core.longpaths=true --config core.symlinks=true`n"
Add-Content C:\buildkite-agent\buildkite-agent.cfg "`ntimestamp-lines=true`n"
# Register the BuildKite agent service using NSSM, so that it persists through restarts and is
# restarted if the process dies.
for ($i=1; $i -le $agents; $i++)
{
$agentName = "buildkite-agent-$i"
Write-Host "Registering $agentName as a service."
nssm.exe install $agentName "C:\buildkite-agent\bin\buildkite-agent.exe" "start"
nssm.exe set $agentName AppStdout "C:\buildkite-agent\$agentName.log"
nssm.exe set $agentName AppStderr "C:\buildkite-agent\$agentName.log"
nssm.exe status $agentName
nssm.exe start $agentName
nssm.exe status $agentName
}
# Restart the machine.
Restart-Computer

View File

@ -28,14 +28,3 @@ test --flaky_test_attempts=2
# More details on failures # More details on failures
build --verbose_failures=true build --verbose_failures=true
# We have seen some flakiness in using TS workers on CircleCI
# https://angular-team.slack.com/archives/C07DT5M6V/p1562693245183400
# > failures like `ERROR: /home/circleci/ng/packages/core/test/BUILD.bazel:5:1:
# > Compiling TypeScript (devmode) //packages/core/test:test_lib failed: Worker process did not return a WorkResponse:`
# > I saw that issue a couple times today.
# > Example job: https://circleci.com/gh/angular/angular/385517
# We expect that TypeScript compilations will parallelize wider than the number of local cores anyway
# so we should saturate remote workers with TS compilations
build --strategy=TypeScriptCompile=standalone
build --strategy=AngularTemplateCompile=standalone

View File

@ -58,7 +58,17 @@ var_5: &setup_bazel_remote_execution
# cause decryption failures based on the openssl version. https://stackoverflow.com/a/39641378/4317734 # cause decryption failures based on the openssl version. https://stackoverflow.com/a/39641378/4317734
openssl aes-256-cbc -d -in .circleci/gcp_token -md md5 -k "$CI_REPO_NAME" -out /home/circleci/.gcp_credentials openssl aes-256-cbc -d -in .circleci/gcp_token -md md5 -k "$CI_REPO_NAME" -out /home/circleci/.gcp_credentials
echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/circleci/.gcp_credentials" >> $BASH_ENV echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/circleci/.gcp_credentials" >> $BASH_ENV
./.circleci/setup-rbe.sh .bazelrc.user touch .bazelrc.user
sudo bash -c "echo -e 'build --config=remote\n' >> .bazelrc.user"
sudo bash -c "echo -e 'build:remote --remote_accept_cached=true\n' >> .bazelrc.user"
echo "Reading from remote cache for bazel remote jobs."
if [[ "$CI_PULL_REQUEST" == "false" ]]; then
sudo bash -c "echo -e 'build:remote --remote_upload_local_results=true\n' >> .bazelrc.user"
echo "Uploading local build results to remote cache."
else
sudo bash -c "echo -e 'build:remote --remote_upload_local_results=false\n' >> .bazelrc.user"
echo "Not uploading local build results to remote cache."
fi
# Settings common to each job # Settings common to each job
var_6: &job_defaults var_6: &job_defaults
@ -128,7 +138,7 @@ var_13: &notify_caretaker_on_fail
# `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings. # `$SLACK_CARETAKER_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
# The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci. # The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
command: | command: |
notificationJson="{\"text\":\":x: \`$CIRCLE_JOB\` job for $CIRCLE_BRANCH branch failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" notificationJson="{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}"
curl --request POST --header "Content-Type: application/json" --data "$notificationJson" $SLACK_CARETAKER_WEBHOOK_URL curl --request POST --header "Content-Type: application/json" --data "$notificationJson" $SLACK_CARETAKER_WEBHOOK_URL
var_14: &notify_dev_infra_on_fail var_14: &notify_dev_infra_on_fail
@ -138,14 +148,9 @@ var_14: &notify_dev_infra_on_fail
# `$SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL` is a secret env var defined in CircleCI project settings. # `$SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL` is a secret env var defined in CircleCI project settings.
# The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci. # The URL comes from https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
command: | command: |
notificationJson="{\"text\":\":x: \`$CIRCLE_JOB\` job for $CIRCLE_BRANCH branch failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" notificationJson="{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}"
curl --request POST --header "Content-Type: application/json" --data "$notificationJson" $SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL curl --request POST --header "Content-Type: application/json" --data "$notificationJson" $SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL
# Cache key for the Material unit tests job. **Note** when updating the SHA in the cache keys,
# also update the SHA for the "MATERIAL_REPO_COMMIT" environment variable.
var_15: &material_unit_tests_cache_key v4-angular-material-701302dc482d7e4b77990b24e3b5ab330bbf1aa5
var_16: &material_unit_tests_cache_key_short v4-angular-material
version: 2 version: 2
jobs: jobs:
setup: setup:
@ -198,13 +203,6 @@ jobs:
# Setup remote execution and run RBE-compatible tests. # Setup remote execution and run RBE-compatible tests.
- *setup_bazel_remote_execution - *setup_bazel_remote_execution
- run: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only - run: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only
- run: mkdir ~/testlogs
- run: cp -Lr dist/testlogs/* ~/testlogs
- store_test_results:
# Bazel always writes test.xml files under this directory
path: ~/testlogs
- store_artifacts:
path: ~/testlogs
# Temporary job to test what will happen when we flip the Ivy flag to true # Temporary job to test what will happen when we flip the Ivy flag to true
test_ivy_aot: test_ivy_aot:
@ -240,11 +238,6 @@ jobs:
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.br path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.br
destination: core/todo/bundle.br destination: core/todo/bundle.br
# This job is currently a PoC for running tests on SauceLabs via bazel. It runs a subset of the
# tests in `legacy-unit-tests-saucelabs` (see
# [BUILD.bazel](https://github.com/angular/angular/blob/ef44f51d5/BUILD.bazel#L66-L92)).
#
# NOTE: This is currently limited to master builds only. See the `default_workflow` configuration.
test_saucelabs_bazel: test_saucelabs_bazel:
<<: *job_defaults <<: *job_defaults
# In order to avoid the bottleneck of having a slow host machine, we acquire a better # In order to avoid the bottleneck of having a slow host machine, we acquire a better
@ -293,8 +286,6 @@ jobs:
- run: yarn --cwd aio e2e --configuration=ci - run: yarn --cwd aio e2e --configuration=ci
# Run PWA-score tests # Run PWA-score tests
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE - run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
# Run accessibility tests
- run: yarn --cwd aio test-a11y-score-localhost
# Check the bundle sizes. # Check the bundle sizes.
- run: yarn --cwd aio payload-size - run: yarn --cwd aio payload-size
# Run unit tests for Firebase redirects # Run unit tests for Firebase redirects
@ -403,7 +394,7 @@ jobs:
# Run examples tests with ivy. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled. # Run examples tests with ivy. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled.
# Since the parallelism is set to "3", there will be three parallel CircleCI containers # Since the parallelism is set to "3", there will be three parallel CircleCI containers
# with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument. # with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument.
- run: yarn --cwd aio example-e2e --setup --local --ivy --cliSpecsConcurrency=5 --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL} - run: yarn --cwd aio example-e2e --setup --local --ivy --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL}
# This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`. # This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`.
aio_preview: aio_preview:
@ -620,55 +611,44 @@ jobs:
resource_class: xlarge resource_class: xlarge
docker: docker:
- image: *browsers_docker_image - image: *browsers_docker_image
# The Material unit tests support splitting the browsers across multiple CircleCI
# instances. Since by default this job launches two browsers, we run each browser
# in its own container instance.
# https://github.com/angular/material2/blob/7baeaa797b19da2d2998f0d26f6fede3c8a13714/test/karma.conf.js#L107-L110
parallelism: 2
environment:
# The Material unit tests also support launching the same browser multiple times by
# sharding individual specs across the defined multiple instances.
# See: https://github.com/angular/material2/blob/7baeaa797b19da2d2998f0d26f6fede3c8a13714/test/karma.conf.js#L113-L116
KARMA_PARALLEL_BROWSERS: 3
steps: steps:
- *attach_workspace - *attach_workspace
- *init_environment - *init_environment
# Although RBE is configured below for the Material repo, also setup RBE in the Angular repo
# to provision Angular's GCP token into the environment variables.
- *setup_bazel_remote_execution
# Restore the cache before cloning the repository because the clone script re-uses
# the restored repository if present. This reduces the amount of times the components
# repository needs to be cloned (this is slow and increases based on commits in the repo).
- restore_cache:
keys:
- *material_unit_tests_cache_key
- *material_unit_tests_cache_key_short
- run: - run:
name: "Fetching Material repository" name: "Cloning Material repository"
command: ./scripts/ci/clone_angular_material_repo.sh command: ./scripts/ci/clone_angular_material_repo.sh
- run: - restore_cache:
# Run yarn install to fetch the Bazel binaries as used in the Material repo.
name: Installing Material dependencies.
command: yarn --cwd ${MATERIAL_REPO_TMP_DIR} install --frozen-lockfile --non-interactive
- save_cache:
key: *material_unit_tests_cache_key
paths:
# Material directory must be kept in sync with the `$MATERIAL_REPO_TMP_DIR` env variable. # Material directory must be kept in sync with the `$MATERIAL_REPO_TMP_DIR` env variable.
# It needs to be hardcoded here, because env variables interpolation is not supported. # It needs to be hardcoded here, because env variables interpolation is not supported.
- "/tmp/material2" keys:
- v2-angular-material-{{ checksum "/tmp/material2/yarn.lock" }}
- v2-angular-material-
- run: - run:
name: "Setup Bazel RBE remote execution in Material repo" name: Installing Material dependencies.
command: | command: yarn --cwd ${MATERIAL_REPO_TMP_DIR} install --frozen-lockfile --non-interactive
./.circleci/setup-rbe.sh "${MATERIAL_REPO_TMP_DIR}/.bazelrc.user" # Save the cache before we run the Material unit tests script. This is necessary
# because we don't want to cache the node modules which have been modified to contain
# the attached Ivy package output.
- save_cache:
# Material directory must be kept in sync with the `$MATERIAL_REPO_TMP_DIR` env variable.
# It needs to be hardcoded here, because env variables interpolation is not supported.
key: v2-angular-material-{{ checksum "/tmp/material2/yarn.lock" }}
paths:
- "/tmp/material2/node_modules"
- run: - run:
name: "Running Material unit tests" name: "Running Material unit tests"
command: ./scripts/ci/run_angular_material_unit_tests.sh command: ./scripts/ci/run_angular_material_unit_tests.sh
test_zonejs:
<<: *job_defaults
steps:
- *attach_workspace
- *init_environment
# Install
- run: yarn --cwd packages/zone.js install --frozen-lockfile --non-interactive
# Run zone.js tools tests
- run: yarn --cwd packages/zone.js promisetest
- run: yarn --cwd packages/zone.js promisefinallytest
- run: yarn bazel build //packages/zone.js:npm_package &&
cp dist/bin/packages/zone.js/npm_package/dist/zone-mix.js ./packages/zone.js/test/extra/ &&
cp dist/bin/packages/zone.js/npm_package/dist/zone-patch-electron.js ./packages/zone.js/test/extra/ &&
yarn --cwd packages/zone.js electrontest
workflows: workflows:
version: 2 version: 2
default_workflow: default_workflow:
@ -689,28 +669,18 @@ workflows:
- build-ivy-npm-packages: - build-ivy-npm-packages:
requires: requires:
- setup - setup
- legacy-misc-tests:
requires:
- build-npm-packages
- legacy-unit-tests-saucelabs:
requires:
- setup
- test_saucelabs_bazel:
requires:
- setup
# This job is currently a PoC and a subset of `legacy-unit-tests-saucelabs`. Running on
# master only to avoid wasting resources.
#
# TODO: Run this job on all branches (including PRs) as soon as it is not a PoC.
filters:
branches:
only: master
- test_aio: - test_aio:
requires: requires:
- setup - setup
- legacy-unit-tests-saucelabs:
requires:
- setup
- deploy_aio: - deploy_aio:
requires: requires:
- test_aio - test_aio
- legacy-misc-tests:
requires:
- build-npm-packages
- test_aio_local: - test_aio_local:
requires: requires:
- build-npm-packages - build-npm-packages
@ -763,9 +733,22 @@ workflows:
- material-unit-tests: - material-unit-tests:
requires: requires:
- build-ivy-npm-packages - build-ivy-npm-packages
- test_zonejs:
saucelabs_tests:
jobs:
- setup
- test_saucelabs_bazel:
requires: requires:
- setup - setup
triggers:
- schedule:
# Runs the Saucelabs legacy tests every hour. We still want to run Saucelabs
# frequently as the caretaker needs up-to-date results when merging PRs or creating
# a new release. Also we primarily moved the Saucelabs job into a cronjob that doesn't
# run for PRs, in order to ensure that PRs are not affected by Saucelabs flakiness or
# incidents. This is still guaranteed (even if we run the job every hour).
cron: "0 * * * *"
filters: *publish_branches_filter
aio_monitoring: aio_monitoring:
jobs: jobs:

View File

@ -77,9 +77,7 @@ setPublicVar SAUCE_READY_FILE_TIMEOUT 120
# their separate build setups. # their separate build setups.
setPublicVar MATERIAL_REPO_TMP_DIR "/tmp/material2" setPublicVar MATERIAL_REPO_TMP_DIR "/tmp/material2"
setPublicVar MATERIAL_REPO_URL "https://github.com/angular/material2.git" setPublicVar MATERIAL_REPO_URL "https://github.com/angular/material2.git"
setPublicVar MATERIAL_REPO_BRANCH "master" setPublicVar MATERIAL_REPO_BRANCH "ivy-2019"
# **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI "config.yml".
setPublicVar MATERIAL_REPO_COMMIT "701302dc482d7e4b77990b24e3b5ab330bbf1aa5"
# Source `$BASH_ENV` to make the variables available immediately. # Source `$BASH_ENV` to make the variables available immediately.
source $BASH_ENV; source $BASH_ENV;

Binary file not shown.

View File

@ -1,20 +0,0 @@
#!/usr/bin/env bash
set -u -e -o pipefail
# The path of the .bazelrc.user file to update should be passed as first parameter to this script.
# This allows to setup RBE for both the Angular repo and the Material repo.
bazelrc_user="$1"
echo "Writing RBE configuration to ${bazelrc_user}"
touch ${bazelrc_user}
echo -e 'build --config=remote\n' >> ${bazelrc_user}
echo -e 'build:remote --remote_accept_cached=true\n' >> ${bazelrc_user}
echo "Reading from remote cache for bazel remote jobs."
if [[ "$CI_PULL_REQUEST" == "false" ]]; then
echo -e 'build:remote --remote_upload_local_results=true\n' >> ${bazelrc_user}
echo "Uploading local build results to remote cache."
else
echo -e 'build:remote --remote_upload_local_results=false\n' >> ${bazelrc_user}
echo "Not uploading local build results to remote cache."
fi

View File

@ -1,5 +1,3 @@
# escape=`
ARG core=mcr.microsoft.com/windows/servercore:1809 ARG core=mcr.microsoft.com/windows/servercore:1809
ARG target=mcr.microsoft.com/powershell:windowsservercore-1809 ARG target=mcr.microsoft.com/powershell:windowsservercore-1809
@ -12,57 +10,57 @@ SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPref
ENV GPG_VERSION 2.3.4 ENV GPG_VERSION 2.3.4
RUN Invoke-WebRequest $('https://files.gpg4win.org/gpg4win-vanilla-{0}.exe' -f $env:GPG_VERSION) -OutFile 'gpg4win.exe' -UseBasicParsing ; ` RUN Invoke-WebRequest $('https://files.gpg4win.org/gpg4win-vanilla-{0}.exe' -f $env:GPG_VERSION) -OutFile 'gpg4win.exe' -UseBasicParsing ; \
Start-Process .\gpg4win.exe -ArgumentList '/S' -NoNewWindow -Wait Start-Process .\gpg4win.exe -ArgumentList '/S' -NoNewWindow -Wait
RUN @( ` RUN @( \
'94AE36675C464D64BAFA68DD7434390BDBE9B9C5', ` '94AE36675C464D64BAFA68DD7434390BDBE9B9C5', \
'FD3A5288F042B6850C66B31F09FE44734EB7990E', ` 'FD3A5288F042B6850C66B31F09FE44734EB7990E', \
'71DCFD284A79C3B38668286BC97EC7A07EDE3FC1', ` '71DCFD284A79C3B38668286BC97EC7A07EDE3FC1', \
'DD8F2338BAE7501E3DD5AC78C273792F7D83545D', ` 'DD8F2338BAE7501E3DD5AC78C273792F7D83545D', \
'C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8', ` 'C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8', \
'B9AE9905FFD7803F25714661B63B535A4C206CA9', ` 'B9AE9905FFD7803F25714661B63B535A4C206CA9', \
'77984A986EBC2AA786BC0F66B01FBB92821C587A', ` '77984A986EBC2AA786BC0F66B01FBB92821C587A', \
'8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600', ` '8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600', \
'4ED778F539E3634C779C87C6D7062848A1AB005C', ` '4ED778F539E3634C779C87C6D7062848A1AB005C', \
'A48C2BEE680E841632CD4E44F07496B3EB3C1762', ` 'A48C2BEE680E841632CD4E44F07496B3EB3C1762', \
'B9E2F5981AA6E0CD28160D9FF13993A75599653C' ` 'B9E2F5981AA6E0CD28160D9FF13993A75599653C' \
) | foreach { ` ) | foreach { \
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys $_ ; ` gpg --keyserver ha.pool.sks-keyservers.net --recv-keys $_ ; \
} }
ENV NODE_VERSION=$node_version ENV NODE_VERSION=$node_version
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/SHASUMS256.txt.asc' -f $env:NODE_VERSION) -OutFile 'SHASUMS256.txt.asc' -UseBasicParsing ; ` RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/SHASUMS256.txt.asc' -f $env:NODE_VERSION) -OutFile 'SHASUMS256.txt.asc' -UseBasicParsing ; \
gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc
RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f $env:NODE_VERSION) -OutFile 'node.zip' -UseBasicParsing ; ` RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f $env:NODE_VERSION) -OutFile 'node.zip' -UseBasicParsing ; \
$sum = $(cat SHASUMS256.txt.asc | sls $(' node-v{0}-win-x64.zip' -f $env:NODE_VERSION)) -Split ' ' ; ` $sum = $(cat SHASUMS256.txt.asc | sls $(' node-v{0}-win-x64.zip' -f $env:NODE_VERSION)) -Split ' ' ; \
if ((Get-FileHash node.zip -Algorithm sha256).Hash -ne $sum[0]) { Write-Error 'SHA256 mismatch' } ; ` if ((Get-FileHash node.zip -Algorithm sha256).Hash -ne $sum[0]) { Write-Error 'SHA256 mismatch' } ; \
Expand-Archive node.zip -DestinationPath C:\ ; ` Expand-Archive node.zip -DestinationPath C:\ ; \
Rename-Item -Path $('C:\node-v{0}-win-x64' -f $env:NODE_VERSION) -NewName 'C:\nodejs' Rename-Item -Path $('C:\node-v{0}-win-x64' -f $env:NODE_VERSION) -NewName 'C:\nodejs'
ENV YARN_VERSION=$yarn_version ENV YARN_VERSION=$yarn_version
RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; ` RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; \
Invoke-WebRequest $('https://yarnpkg.com/downloads/{0}/yarn-{0}.msi' -f $env:YARN_VERSION) -OutFile yarn.msi -UseBasicParsing ; ` Invoke-WebRequest $('https://yarnpkg.com/downloads/{0}/yarn-{0}.msi' -f $env:YARN_VERSION) -OutFile yarn.msi -UseBasicParsing ; \
$sig = Get-AuthenticodeSignature yarn.msi ; ` $sig = Get-AuthenticodeSignature yarn.msi ; \
if ($sig.Status -ne 'Valid') { Write-Error 'Authenticode signature is not valid' } ; ` if ($sig.Status -ne 'Valid') { Write-Error 'Authenticode signature is not valid' } ; \
Write-Output $sig.SignerCertificate.Thumbprint ; ` Write-Output $sig.SignerCertificate.Thumbprint ; \
if (@( ` if (@( \
'7E253367F8A102A91D04829E37F3410F14B68A5F', ` '7E253367F8A102A91D04829E37F3410F14B68A5F', \
'AF764E1EA56C762617BDC757C8B0F3780A0CF5F9' ` 'AF764E1EA56C762617BDC757C8B0F3780A0CF5F9' \
) -notcontains $sig.SignerCertificate.Thumbprint) { Write-Error 'Unknown signer certificate' } ; ` ) -notcontains $sig.SignerCertificate.Thumbprint) { Write-Error 'Unknown signer certificate' } ; \
Start-Process msiexec.exe -ArgumentList '/i', 'yarn.msi', '/quiet', '/norestart' -NoNewWindow -Wait Start-Process msiexec.exe -ArgumentList '/i', 'yarn.msi', '/quiet', '/norestart' -NoNewWindow -Wait
ENV GIT_VERSION 2.20.1 ENV GIT_VERSION 2.20.1
ENV GIT_DOWNLOAD_URL https://github.com/git-for-windows/git/releases/download/v${GIT_VERSION}.windows.1/MinGit-${GIT_VERSION}-busybox-64-bit.zip ENV GIT_DOWNLOAD_URL https://github.com/git-for-windows/git/releases/download/v${GIT_VERSION}.windows.1/MinGit-${GIT_VERSION}-busybox-64-bit.zip
ENV GIT_SHA256 9817ab455d9cbd0b09d8664b4afbe4bbf78d18b556b3541d09238501a749486c ENV GIT_SHA256 9817ab455d9cbd0b09d8664b4afbe4bbf78d18b556b3541d09238501a749486c
RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; ` RUN [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 ; \
Invoke-WebRequest -UseBasicParsing $env:GIT_DOWNLOAD_URL -OutFile git.zip; ` Invoke-WebRequest -UseBasicParsing $env:GIT_DOWNLOAD_URL -OutFile git.zip; \
if ((Get-FileHash git.zip -Algorithm sha256).Hash -ne $env:GIT_SHA256) {exit 1} ; ` if ((Get-FileHash git.zip -Algorithm sha256).Hash -ne $env:GIT_SHA256) {exit 1} ; \
Expand-Archive git.zip -DestinationPath C:\git; ` Expand-Archive git.zip -DestinationPath C:\git; \
Remove-Item git.zip Remove-Item git.zip
FROM $target as baseimage FROM $target as baseimage
@ -82,45 +80,24 @@ FROM baseimage
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
# Install Bazel prereqs on Windows (https://docs.bazel.build/versions/master/install-windows.html) RUN Invoke-WebRequest -UseBasicParsing 'https://www.7-zip.org/a/7z1805-x64.exe' -OutFile 7z.exe; \
Start-Process -FilePath 'C:\\7z.exe' -ArgumentList '/S', '/D=C:\\7zip0' -NoNewWindow -Wait; \
Invoke-WebRequest -UseBasicParsing 'http://repo.msys2.org/distrib/x86_64/msys2-base-x86_64-20180531.tar.xz' -OutFile msys2.tar.xz; \
Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'e', 'msys2.tar.xz' -Wait; \
Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'x', 'msys2.tar', '-oC:\\' -Wait; \
Remove-Item msys2.tar.xz; \
Remove-Item msys2.tar; \
Remove-Item 7z.exe; \
Remove-Item -Recurse 7zip; \
[Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\msys64\usr\bin', [System.EnvironmentVariableTarget]::Machine); \
[Environment]::SetEnvironmentVariable('BAZEL_SH', 'C:\msys64\usr\bin\bash.exe', [System.EnvironmentVariableTarget]::Machine); \
Invoke-WebRequest -UseBasicParsing 'https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x64.exe' -OutFile vc_redist.x64.exe; \
Start-Process 'c:\\vc_redist.x64.exe' -ArgumentList '/Install', '/Passive', '/NoRestart' -NoNewWindow -Wait; \
Remove-Item vc_redist.x64.exe
# Install MSYS2 # Add a fix for https://github.com/docker/for-win/issues/2920 as entry point to the container.
RUN Invoke-WebRequest -UseBasicParsing 'https://www.7-zip.org/a/7z1805-x64.exe' -OutFile 7z.exe; ` SHELL ["cmd", "/c"]
Start-Process -FilePath 'C:\\7z.exe' -ArgumentList '/S', '/D=C:\\7zip0' -NoNewWindow -Wait; ` COPY "fix-msys64.cmd" "C:\\fix-msys64.cmd"
Invoke-WebRequest -UseBasicParsing 'http://repo.msys2.org/distrib/x86_64/msys2-base-x86_64-20180531.tar.xz' -OutFile msys2.tar.xz; ` ENTRYPOINT cmd /C C:\\fix-msys64.cmd && cmd /c
Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'e', 'msys2.tar.xz' -Wait; `
Start-Process -FilePath 'C:\\7zip\\7z' -ArgumentList 'x', 'msys2.tar', '-oC:\\' -Wait; `
Remove-Item msys2.tar.xz; `
Remove-Item msys2.tar; `
Remove-Item 7z.exe; `
Remove-Item -Recurse 7zip; `
[Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\msys64\usr\bin', [System.EnvironmentVariableTarget]::Machine); `
[Environment]::SetEnvironmentVariable('BAZEL_SH', 'C:\msys64\usr\bin\bash.exe', [System.EnvironmentVariableTarget]::Machine)
# Install MSYS2 packages
RUN C:\msys64\usr\bin\bash.exe -l -c \"pacman --needed --noconfirm -S zip unzip patch diffutils git\"
# Install VS Build Tools (required to build C++ targets)
RUN Invoke-WebRequest -UseBasicParsing https://download.visualstudio.microsoft.com/download/pr/df649173-11e9-4af2-8eb7-0eb02ba8958a/cadb5bdac41e55bb8f6a6b7c45273370/vs_buildtools.exe -OutFile vs_BuildTools.exe; `
# Installer won't detect DOTNET_SKIP_FIRST_TIME_EXPERIENCE if ENV is used, must use setx /M
setx /M DOTNET_SKIP_FIRST_TIME_EXPERIENCE 1; `
Start-Process vs_BuildTools.exe `
-ArgumentList `
'--add', 'Microsoft.VisualStudio.Workload.VCTools', `
'--add', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', `
'--add', 'Microsoft.Component.VC.Runtime.UCRTSDK', `
'--add', 'Microsoft.VisualStudio.Component.Windows10SDK.17763', `
'--quiet', '--norestart', '--nocache' `
-NoNewWindow -Wait; `
Remove-Item -Force vs_buildtools.exe; `
Remove-Item -Force -Recurse \"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\"; `
Remove-Item -Force -Recurse ${Env:TEMP}\*; `
Remove-Item -Force -Recurse \"${Env:ProgramData}\Package Cache\"; `
[Environment]::SetEnvironmentVariable('BAZEL_VC', \"${Env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\BuildTools\VC\", [System.EnvironmentVariableTarget]::Machine)
# Install Python (required to build Python targets)
RUN Invoke-WebRequest -UseBasicParsing https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile python-3.5.1.exe; `
Start-Process python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait; `
Remove-Item -Force python-3.5.1.exe
CMD ["cmd.exe"] CMD ["cmd.exe"]

View File

@ -2,17 +2,11 @@
# We do this by copying this file to /etc/bazel.bazelrc at the start of the build. # We do this by copying this file to /etc/bazel.bazelrc at the start of the build.
# See documentation in /docs/BAZEL.md # See documentation in /docs/BAZEL.md
# Save built files and downloaded repositories in a location that can be cached by CodeFresh and # Save downloaded repositories in a location that can be cached by CodeFresh and shared between
# shared between builds. This helps speed up the analysis time significantly with Bazel managed node # builds. This helps speed up the analysis time significantly with Bazel managed node dependencies
# dependencies on the CI. # on the CI.
# https://codefresh.io/docs/docs/configure-ci-cd-pipeline/introduction-to-codefresh-pipelines/#caching-the-artifacts-of-your-build-system # https://codefresh.io/docs/docs/configure-ci-cd-pipeline/introduction-to-codefresh-pipelines/#caching-the-artifacts-of-your-build-system
build --repository_cache=C:/codefresh/volume/bazel_repository_cache build --repository_cache=C:/codefresh/volume/bazel_repository_cache
# Setting the output_base to a Docker volume is currently broken because of a Docker bug on Windows:
# https://github.com/moby/moby/issues/37024
# This affects Bazel because bazel_output_base\external\bazel_tools is an absolute path junction.
# When its fixed we can uncomment this line, and use a different output_base for Ivy tests (they
# use a separate compiler and destructively replace the cache).
# startup --output_base=C:/codefresh/volume/bazel_output_base
# Don't be spammy in the logs # Don't be spammy in the logs
# TODO(gmagolan): Hide progress again once build performance improves # TODO(gmagolan): Hide progress again once build performance improves
@ -29,10 +23,20 @@ build --announce_rc
# Bazel doesn't calculate the memory ceiling correctly when running under Docker. # Bazel doesn't calculate the memory ceiling correctly when running under Docker.
# Limit Bazel to consuming resources that fit in CodeFresh VMs # Limit Bazel to consuming resources that fit in CodeFresh VMs
# TODO(filipesilva): determine the correct memory limit # TODO(filipesilva): determine the correct memory limit
build --local_resources=10240,8.0,1.0 build --local_resources=8000,8.0,1.0
# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309 # Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309
test --flaky_test_attempts=2 test --flaky_test_attempts=2
# More details on failures # More details on failures
build --verbose_failures=true build --verbose_failures=true
# Include PATH in Windows build/tests
# https://github.com/bazelbuild/rules_typescript/pull/356
build --action_env=PATH
test --action_env=PATH --test_env=PATH
# Exclude tests known to not work on Windows.
# Chrome web tests are currently broken.
test --test_tag_filters=-browser:chromium-local

View File

@ -2,7 +2,6 @@ version: '1.0'
steps: steps:
BuildImage: BuildImage:
title: Build Docker image
type: build type: build
image_name: node-bazel-windows image_name: node-bazel-windows
working_directory: ./.codefresh working_directory: ./.codefresh
@ -13,7 +12,7 @@ steps:
dockerfile: ./Dockerfile.win-1809 dockerfile: ./Dockerfile.win-1809
RunTests: RunTests:
title: Run Bazel tests title: Run Example
image: ${{BuildImage}} image: ${{BuildImage}}
commands: commands:
# Install dependencies # Install dependencies
@ -21,8 +20,7 @@ steps:
# Add Bazel CI config # Add Bazel CI config
- copy .codefresh\bazel.rc %ProgramData%\bazel.bazelrc - copy .codefresh\bazel.rc %ProgramData%\bazel.bazelrc
# Run tests # Run tests
# At the moment 'browser:chromium-local' are broken in CI while locally they work - yarn bazel test //tools/ts-api-guardian:all //packages/language-service/test //packages/compiler/test //packages/compiler-cli/test:ngc //packages/compiler-cli/test/ngtsc:ngtsc
# VE - yarn test-ivy-aot //packages/animations/test //packages/common/test //packages/forms/test //packages/http/test //packages/platform-browser/test //packages/platform-browser-dynamic/test //packages/router/test
- yarn bazel test --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only,-browser:chromium-local //... - yarn bazel test //tools/public_api_guard/...
# Ivy - yarn bazel test //packages/compiler-cli/integrationtest:integrationtest //packages/compiler-cli/test/compliance:compliance
- yarn bazel test --define=compile=aot --build_tag_filters=-no-ivy-aot,-fixme-ivy-aot --test_tag_filters=-no-ivy-aot,-fixme-ivy-aot,-browser:chromium-local //...

View File

@ -0,0 +1,6 @@
@echo off
REM Fix for https://github.com/docker/for-win/issues/2920
REM echo "Fixing msys64 folder..."
REM Touch all .dll files inside C:\msys64\
forfiles /p C:\msys64\ /s /m *.dll /c "cmd /c Copy /B @path+,, >NUL"
REM echo "Fixed msys64 folder."

View File

@ -18,15 +18,15 @@ filegroup(
name = "web_test_bootstrap_scripts", name = "web_test_bootstrap_scripts",
# do not sort # do not sort
srcs = [ srcs = [
"@npm//:node_modules/core-js/client/core.js", "@npm//node_modules/core-js:client/core.js",
"@npm//:node_modules/zone.js/dist/zone.js", "@npm//node_modules/zone.js:dist/zone.js",
"@npm//:node_modules/zone.js/dist/zone-testing.js", "@npm//node_modules/zone.js:dist/zone-testing.js",
"@npm//:node_modules/zone.js/dist/task-tracking.js", "@npm//node_modules/zone.js:dist/task-tracking.js",
"//:test-events.js", "//:test-events.js",
"//:shims_for_IE.js", "//:shims_for_IE.js",
# Including systemjs because it defines `__eval`, which produces correct stack traces. # Including systemjs because it defines `__eval`, which produces correct stack traces.
"@npm//:node_modules/systemjs/dist/system.src.js", "@npm//node_modules/systemjs:dist/system.src.js",
"@npm//:node_modules/reflect-metadata/Reflect.js", "@npm//node_modules/reflect-metadata:Reflect.js",
], ],
) )
@ -35,15 +35,15 @@ filegroup(
srcs = [ srcs = [
# We also declare the unminfied AngularJS files since these can be used for # We also declare the unminfied AngularJS files since these can be used for
# local debugging (e.g. see: packages/upgrade/test/common/test_helpers.ts) # local debugging (e.g. see: packages/upgrade/test/common/test_helpers.ts)
"@npm//:node_modules/angular/angular.js", "@npm//node_modules/angular:angular.js",
"@npm//:node_modules/angular/angular.min.js", "@npm//node_modules/angular:angular.min.js",
"@npm//:node_modules/angular-1.5/angular.js", "@npm//node_modules/angular-1.5:angular.js",
"@npm//:node_modules/angular-1.5/angular.min.js", "@npm//node_modules/angular-1.5:angular.min.js",
"@npm//:node_modules/angular-1.6/angular.js", "@npm//node_modules/angular-1.6:angular.js",
"@npm//:node_modules/angular-1.6/angular.min.js", "@npm//node_modules/angular-1.6:angular.min.js",
"@npm//:node_modules/angular-mocks/angular-mocks.js", "@npm//node_modules/angular-mocks:angular-mocks.js",
"@npm//:node_modules/angular-mocks-1.5/angular-mocks.js", "@npm//node_modules/angular-mocks-1.5:angular-mocks.js",
"@npm//:node_modules/angular-mocks-1.6/angular-mocks.js", "@npm//node_modules/angular-mocks-1.6:angular-mocks.js",
], ],
) )
@ -74,7 +74,6 @@ karma_web_test(
"//packages/core/test:test_lib", "//packages/core/test:test_lib",
"//packages/forms/test:test_lib", "//packages/forms/test:test_lib",
"//packages/http/test:test_lib", "//packages/http/test:test_lib",
"//packages/zone.js/test:karma_jasmine_test_ci",
# "//packages/router/test:test_lib", # "//packages/router/test:test_lib",
# //packages/router/test:test_lib fails with: # //packages/router/test:test_lib fails with:
# IE 11.0.0 (Windows 8.1.0.0) bootstrap should restore the scrolling position FAILED # IE 11.0.0 (Windows 8.1.0.0) bootstrap should restore the scrolling position FAILED

View File

@ -1,72 +1,3 @@
<a name="8.1.3"></a>
## [8.1.3](https://github.com/angular/angular/compare/8.1.2...8.1.3) (2019-07-30)
### Bug Fixes
* **elements:** handle falsy initial value ([#31604](https://github.com/angular/angular/issues/31604)) ([434b796](https://github.com/angular/angular/commit/434b796)), closes [angular/angular#30834](https://github.com/angular/angular/issues/30834)
### Performance Improvements
* **compiler:** avoid copying from prototype while cloning an object ([#31638](https://github.com/angular/angular/issues/31638)) ([1f3daa0](https://github.com/angular/angular/commit/1f3daa0)), closes [#31627](https://github.com/angular/angular/issues/31627)
<a name="8.1.2"></a>
## [8.1.2](https://github.com/angular/angular/compare/8.1.0...8.1.2) (2019-07-17)
### Bug Fixes
* use the correct WTF array to iterate over ([#31208](https://github.com/angular/angular/issues/31208)) ([4aed480](https://github.com/angular/angular/commit/4aed480))
* **compiler-cli:** Return original sourceFile instead of redirected sourceFile from getSourceFile ([#26036](https://github.com/angular/angular/issues/26036)) ([13dbb98](https://github.com/angular/angular/commit/13dbb98)), closes [#22524](https://github.com/angular/angular/issues/22524)
* **core:** export provider interfaces that are part of the public API types ([#31377](https://github.com/angular/angular/issues/31377)) ([bebf089](https://github.com/angular/angular/commit/bebf089)), closes [/github.com/angular/angular/pull/31377#discussion_r299254408](https://github.com//github.com/angular/angular/pull/31377/issues/discussion_r299254408) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L365-L366](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L365-L366) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L283-L284](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L283-L284) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts#L23](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts/issues/L23)
<a name="8.1.1"></a>
## [8.1.1](https://github.com/angular/angular/compare/8.1.0...8.1.1) (2019-07-10)
### Bug Fixes
* **core:** export provider interfaces that are part of the public API types ([#31377](https://github.com/angular/angular/issues/31377)) ([bebf089](https://github.com/angular/angular/commit/bebf089)), closes [/github.com/angular/angular/pull/31377#discussion_r299254408](https://github.com//github.com/angular/angular/pull/31377/issues/discussion_r299254408) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L365-L366](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L365-L366) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts#L283-L284](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/interface/provider.ts/issues/L283-L284) [/github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts#L23](https://github.com//github.com/angular/angular/blob/9e34670b2/packages/core/src/di/index.ts/issues/L23)
<a name="8.1.0"></a>
# [8.1.0](https://github.com/angular/angular/compare/8.1.0-rc.0...8.1.0) (2019-07-02)
### Bug Fixes
* **core:** handle `undefined` meta in `injectArgs` ([#31333](https://github.com/angular/angular/issues/31333)) ([80ccd6c](https://github.com/angular/angular/commit/80ccd6c)), closes [CLI #14888](https://github.com/angular/angular-cli/issues/14888)
* **service-worker:** cache opaque responses in data groups with `freshness` strategy ([#30977](https://github.com/angular/angular/issues/30977)) ([b0c3453](https://github.com/angular/angular/commit/b0c3453)), closes [#30968](https://github.com/angular/angular/issues/30968)
* **service-worker:** cache opaque responses when requests exceeds timeout threshold ([#30977](https://github.com/angular/angular/issues/30977)) ([a9038ef](https://github.com/angular/angular/commit/a9038ef))
<a name="8.1.0-rc.0"></a>
# [8.1.0-rc.0](https://github.com/angular/angular/compare/8.1.0-next.3...8.1.0-rc.0) (2019-06-26)
### Bug Fixes
* **bazel:** exclude all angular schematics folders from metadata build ([#31237](https://github.com/angular/angular/issues/31237)) ([16717fa](https://github.com/angular/angular/commit/16717fa)), closes [#31235](https://github.com/angular/angular/issues/31235)
* **bazel:** remove unsupported Css pre-processors from ng new ([#31234](https://github.com/angular/angular/issues/31234)) ([e83667a](https://github.com/angular/angular/commit/e83667a)), closes [#31209](https://github.com/angular/angular/issues/31209)
* **bazel:** update ng new schema to match the current ng new schema of [@schematics](https://github.com/schematics)/angular ([#31234](https://github.com/angular/angular/issues/31234)) ([805fc86](https://github.com/angular/angular/commit/805fc86)), closes [#31233](https://github.com/angular/angular/issues/31233)
* **compiler:** fix Elements not making a new ParseSourceSpan ([#31190](https://github.com/angular/angular/issues/31190)) ([7035f22](https://github.com/angular/angular/commit/7035f22))
* **compiler:** stringify `Object.create(null)` tokens ([#16848](https://github.com/angular/angular/issues/16848)) ([5e53956](https://github.com/angular/angular/commit/5e53956))
* **service-worker:** registration failed on Safari ([#31140](https://github.com/angular/angular/issues/31140)) ([a5dd4ed](https://github.com/angular/angular/commit/a5dd4ed)), closes [#31061](https://github.com/angular/angular/issues/31061)
### Features
* **upgrade:** provide unit test helpers for wiring up injectors ([#16848](https://github.com/angular/angular/issues/16848)) ([3fb78aa](https://github.com/angular/angular/commit/3fb78aa))
<a name="8.0.3"></a> <a name="8.0.3"></a>
## [8.0.3](https://github.com/angular/angular/compare/8.0.2...8.0.3) (2019-06-26) ## [8.0.3](https://github.com/angular/angular/compare/8.0.2...8.0.3) (2019-06-26)
@ -80,18 +11,6 @@
<a name="8.1.0-next.3"></a>
# [8.1.0-next.3](https://github.com/angular/angular/compare/8.1.0-next.2...8.1.0-next.3) (2019-06-19)
### Bug Fixes
* **bazel:** builder workspace should use nodejs v10.16.0 ([#31088](https://github.com/angular/angular/issues/31088)) ([a1fc4de](https://github.com/angular/angular/commit/a1fc4de))
* **core:** temporarily remove [@deprecated](https://github.com/deprecated) jsdoc tag for a TextBedStatic.get overload ([#30714](https://github.com/angular/angular/issues/30714)) ([6bc9c78](https://github.com/angular/angular/commit/6bc9c78)), closes [#30514](https://github.com/angular/angular/issues/30514)
* **language-service:** Remove 'any' in getQuickInfoAtPosition ([#31014](https://github.com/angular/angular/issues/31014)) ([a4601ec](https://github.com/angular/angular/commit/a4601ec))
<a name="8.0.2"></a> <a name="8.0.2"></a>
## [8.0.2](https://github.com/angular/angular/compare/8.0.1...8.0.2) (2019-06-19) ## [8.0.2](https://github.com/angular/angular/compare/8.0.1...8.0.2) (2019-06-19)
@ -104,20 +23,6 @@
<a name="8.1.0-next.2"></a>
# [8.1.0-next.2](https://github.com/angular/angular/compare/8.1.0-next.1...8.1.0-next.2) (2019-06-13)
### Bug Fixes
* **bazel:** do not modify tsconfig.json ([#30877](https://github.com/angular/angular/issues/30877)) ([b086676](https://github.com/angular/angular/commit/b086676))
* **bazel:** exclude components schematics from build ([#30825](https://github.com/angular/angular/issues/30825)) ([05a43ca](https://github.com/angular/angular/commit/05a43ca))
* **bazel:** Load global stylesheet in dev and prod ([#30879](https://github.com/angular/angular/issues/30879)) ([17bfedd](https://github.com/angular/angular/commit/17bfedd))
* **common:** expose the `HttpUploadProgressEvent` interface as public API ([#30852](https://github.com/angular/angular/issues/30852)) ([5c18f23](https://github.com/angular/angular/commit/5c18f23)), closes [#30814](https://github.com/angular/angular/issues/30814)
* **service-worker:** avoid uncaught rejection warning when registration fails ([#30876](https://github.com/angular/angular/issues/30876)) ([81c2a94](https://github.com/angular/angular/commit/81c2a94))
<a name="8.0.1"></a> <a name="8.0.1"></a>
## [8.0.1](https://github.com/angular/angular/compare/8.0.0...8.0.1) (2019-06-13) ## [8.0.1](https://github.com/angular/angular/compare/8.0.0...8.0.1) (2019-06-13)
@ -132,83 +37,24 @@
<a name="8.1.0-next.1"></a>
# [8.1.0-next.1](https://github.com/angular/angular/compare/8.1.0-beta.0...8.1.0-next.1) (2019-06-05)
### Bug Fixes
* **core:** TypeScript related migrations should cater for BOM ([#30719](https://github.com/angular/angular/issues/30719)) ([80394ce](https://github.com/angular/angular/commit/80394ce)), closes [/github.com/angular/angular-cli/blob/master/packages/angular_devkit/schematics/src/tree/recorder.ts#L72](https://github.com//github.com/angular/angular-cli/blob/master/packages/angular_devkit/schematics/src/tree/recorder.ts/issues/L72) [#30713](https://github.com/angular/angular/issues/30713)
<a name="8.1.0-beta.0"></a>
# [8.1.0-beta.0](https://github.com/angular/angular/compare/8.0.0...8.1.0-beta.0) (2019-05-30)
### Bug Fixes
* **bazel:** allow ts_library interop with list-typed inputs ([#30600](https://github.com/angular/angular/issues/30600)) ([3125376](https://github.com/angular/angular/commit/3125376))
* **bazel:** Bump ibazel to 0.10.1 for windows fixes ([#30196](https://github.com/angular/angular/issues/30196)) ([1353bf0](https://github.com/angular/angular/commit/1353bf0))
* **bazel:** Directly spawn native Bazel binary ([#30306](https://github.com/angular/angular/issues/30306)) ([2a0f497](https://github.com/angular/angular/commit/2a0f497))
* **bazel:** Disable sandbox on Mac OS ([#30460](https://github.com/angular/angular/issues/30460)) ([b6b1aec](https://github.com/angular/angular/commit/b6b1aec))
* **bazel:** Exclude common/upgrade* in metadata.tsconfig.json ([#30133](https://github.com/angular/angular/issues/30133)) ([1f4c380](https://github.com/angular/angular/commit/1f4c380))
* **bazel:** ng test should run specific ts_web_test_suite ([#30526](https://github.com/angular/angular/issues/30526)) ([e688e02](https://github.com/angular/angular/commit/e688e02))
* **bazel:** pass correct arguments to http_server in Windows ([#30346](https://github.com/angular/angular/issues/30346)) ([3aff79c](https://github.com/angular/angular/commit/3aff79c)), closes [#29785](https://github.com/angular/angular/issues/29785)
* **bazel:** update peerDep ranges ([#30155](https://github.com/angular/angular/issues/30155)) ([4ae0ee8](https://github.com/angular/angular/commit/4ae0ee8))
* **bazel:** Use existing npm/yarn lock files ([#30438](https://github.com/angular/angular/issues/30438)) ([ff29ccc](https://github.com/angular/angular/commit/ff29ccc))
* **compiler-cli:** log ngcc skipping messages as debug instead of info ([#30232](https://github.com/angular/angular/issues/30232)) ([60a8888](https://github.com/angular/angular/commit/60a8888))
* **core:** consistently use ng:/// for sourcemap URLs ([#29826](https://github.com/angular/angular/issues/29826)) ([392473e](https://github.com/angular/angular/commit/392473e))
* **core:** CSS sanitizer now allows parens in file names ([#30322](https://github.com/angular/angular/issues/30322)) ([728db88](https://github.com/angular/angular/commit/728db88))
* **core:** fix interpolate identifier in AOT ([#30243](https://github.com/angular/angular/issues/30243)) ([30d1f29](https://github.com/angular/angular/commit/30d1f29))
* **core:** migrations not always migrating all files ([#30269](https://github.com/angular/angular/issues/30269)) ([349935a](https://github.com/angular/angular/commit/349935a))
* **core:** remove deprecated `TestBed.deprecatedOverrideProvider` API ([#30576](https://github.com/angular/angular/issues/30576)) ([a96976e](https://github.com/angular/angular/commit/a96976e))
* **core:** require 'static' flag on queries in typings ([#30639](https://github.com/angular/angular/issues/30639)) ([84dd267](https://github.com/angular/angular/commit/84dd267))
* **core:** static-query migration errors not printed properly ([#30458](https://github.com/angular/angular/issues/30458)) ([6ceb903](https://github.com/angular/angular/commit/6ceb903))
* **core:** static-query migration fails with default parameter values ([#30269](https://github.com/angular/angular/issues/30269)) ([6357d4a](https://github.com/angular/angular/commit/6357d4a))
* **core:** static-query migration should gracefully exit if AOT compiler throws ([#30269](https://github.com/angular/angular/issues/30269)) ([509352f](https://github.com/angular/angular/commit/509352f))
* **core:** static-query migration should handle queries on accessors ([#30327](https://github.com/angular/angular/issues/30327)) ([0ffdb48](https://github.com/angular/angular/commit/0ffdb48))
* **core:** static-query migration should not fallback to test strategy ([#30458](https://github.com/angular/angular/issues/30458)) ([0cdf598](https://github.com/angular/angular/commit/0cdf598))
* **core:** static-query migration should not prompt if no queries are used ([#30254](https://github.com/angular/angular/issues/30254)) ([4c12d74](https://github.com/angular/angular/commit/4c12d74))
* **core:** static-query usage migration strategy should detect ambiguous query usage ([#30215](https://github.com/angular/angular/issues/30215)) ([8d3365e](https://github.com/angular/angular/commit/8d3365e))
* **core:** temporarily remove [@deprecated](https://github.com/deprecated) jsdoc tag for a TextBed.get overload ([#30514](https://github.com/angular/angular/issues/30514)) ([f6bf892](https://github.com/angular/angular/commit/f6bf892)), closes [#29290](https://github.com/angular/angular/issues/29290) [#29905](https://github.com/angular/angular/issues/29905)
* **language-service:** Remove tsserverlibrary from rollup globals ([#30123](https://github.com/angular/angular/issues/30123)) ([124e497](https://github.com/angular/angular/commit/124e497))
* **router:** ensure `history.state` is set in `eager` update mode ([#30154](https://github.com/angular/angular/issues/30154)) ([b40f6f3](https://github.com/angular/angular/commit/b40f6f3))
* **router:** ensure navigations start with the current URL value incase redirect is skipped ([#30344](https://github.com/angular/angular/issues/30344)) ([0fd9d08](https://github.com/angular/angular/commit/0fd9d08)), closes [#30340](https://github.com/angular/angular/issues/30340) [#30160](https://github.com/angular/angular/issues/30160)
* **router:** fix a problem with router not responding to back button ([#30160](https://github.com/angular/angular/issues/30160)) ([3327bd8](https://github.com/angular/angular/commit/3327bd8))
* **router:** IE 11 bug can break URL unification when comparing objects ([#30393](https://github.com/angular/angular/issues/30393)) ([197584d](https://github.com/angular/angular/commit/197584d))
* **router:** type cast correctly for IE 11 bug breaking URL Unification when comparing objects ([#30464](https://github.com/angular/angular/issues/30464)) ([53f3564](https://github.com/angular/angular/commit/53f3564))
### Features
* **bazel:** use `rbe_autoconfig()` and new container. ([#29336](https://github.com/angular/angular/issues/29336)) ([9abf114](https://github.com/angular/angular/commit/9abf114))
* **common:** add ability to watch for AngularJS URL updates through `onUrlChange` hook ([#30466](https://github.com/angular/angular/issues/30466)) ([1aff524](https://github.com/angular/angular/commit/1aff524))
* **common:** stricter types for `SlicePipe` ([#30156](https://github.com/angular/angular/issues/30156)) ([95830ee](https://github.com/angular/angular/commit/95830ee))
* **core:** deprecate integration with the Web Tracing Framework (WTF) ([#30642](https://github.com/angular/angular/issues/30642)) ([f310a59](https://github.com/angular/angular/commit/f310a59))
* **language-service:** Implement `definitionAndBoundSpan` ([#30125](https://github.com/angular/angular/issues/30125)) ([f491673](https://github.com/angular/angular/commit/f491673))
* **platform-webworker:** deprecate platform-webworker ([#30642](https://github.com/angular/angular/issues/30642)) ([ccc76f7](https://github.com/angular/angular/commit/ccc76f7))
<a name="8.0.0"></a> <a name="8.0.0"></a>
# [8.0.0](https://github.com/angular/angular/compare/8.0.0-rc.5...8.0.0) (2019-05-28) # [8.0.0](https://github.com/angular/angular/compare/8.0.0-rc.5...8.0.0) (2019-05-28)
### Features ### Features
* add support for TypeScript 3.4 (and drop older versions) ([#29372](https://github.com/angular/angular/issues/29372)) ([ef85336](https://github.com/angular/angular/commit/ef85336)) * add support for TypeScript 3.3 (and drop older versions) ([#29004](https://github.com/angular/angular/issues/29004)) ([75748d6](https://github.com/angular/angular/commit/75748d6))
* **common:** add ability to watch for AngularJS URL updates through `onUrlChange` hook ([#30466](https://github.com/angular/angular/issues/30466)) ([8022d36](https://github.com/angular/angular/commit/8022d36)) * **common:** add ability to watch for AngularJS URL updates through `onUrlChange` hook ([#30466](https://github.com/angular/angular/issues/30466)) ([8022d36](https://github.com/angular/angular/commit/8022d36))
* **common:** stricter types for `SlicePipe` ([#30156](https://github.com/angular/angular/issues/30156)) ([722b2fa](https://github.com/angular/angular/commit/722b2fa)) * **common:** stricter types for SlicePipe ([#30156](https://github.com/angular/angular/issues/30156)) ([722b2fa](https://github.com/angular/angular/commit/722b2fa))
* **bazel:** use `rbe_autoconfig()` and new container ([#29336](https://github.com/angular/angular/issues/29336)) ([e562acc](https://github.com/angular/angular/commit/e562acc)) * **bazel:** use rbe_autoconfig() and new container. ([#29336](https://github.com/angular/angular/issues/29336)) ([e562acc](https://github.com/angular/angular/commit/e562acc))
* **common:** add @angular/common/upgrade package for `$location`-related APIs ([#30055](https://github.com/angular/angular/issues/30055)) ([152d99e](https://github.com/angular/angular/commit/152d99e)) * **common:** add [@angular](https://github.com/angular)/common/upgrade package for $location-related APIs ([#30055](https://github.com/angular/angular/issues/30055)) ([152d99e](https://github.com/angular/angular/commit/152d99e))
* **common:** add ability to retrieve the state from `Location` service ([#30055](https://github.com/angular/angular/issues/30055)) ([b44b143](https://github.com/angular/angular/commit/b44b143)) * **common:** add ability to retrieve the state from Location service ([#30055](https://github.com/angular/angular/issues/30055)) ([b44b143](https://github.com/angular/angular/commit/b44b143))
* **common:** add ability to track all location changes ([#30055](https://github.com/angular/angular/issues/30055)) ([3a9cf3f](https://github.com/angular/angular/commit/3a9cf3f)) * **common:** add ability to track all location changes ([#30055](https://github.com/angular/angular/issues/30055)) ([3a9cf3f](https://github.com/angular/angular/commit/3a9cf3f))
* **common:** add APIs to read component pieces of URL ([#30055](https://github.com/angular/angular/issues/30055)) ([b635fe8](https://github.com/angular/angular/commit/b635fe8)) * **common:** add APIs to read component pieces of URL ([#30055](https://github.com/angular/angular/issues/30055)) ([b635fe8](https://github.com/angular/angular/commit/b635fe8))
* **common:** add `MockPlatformLocation` to enable more robust testing of `Location` services ([#30055](https://github.com/angular/angular/issues/30055)) ([d0672c2](https://github.com/angular/angular/commit/d0672c2)) * **common:** add MockPlatformLocation to enable more robust testing of Location services ([#30055](https://github.com/angular/angular/issues/30055)) ([d0672c2](https://github.com/angular/angular/commit/d0672c2))
* **common:** add `UrlCodec` type for use with upgrade applications ([#30055](https://github.com/angular/angular/issues/30055)) ([ec455e1](https://github.com/angular/angular/commit/ec455e1)) * **common:** add UrlCodec type for use with upgrade applications ([#30055](https://github.com/angular/angular/issues/30055)) ([ec455e1](https://github.com/angular/angular/commit/ec455e1))
* **common:** provide replacement for AngularJS $location service ([#30055](https://github.com/angular/angular/issues/30055)) ([4277600](https://github.com/angular/angular/commit/4277600)) * **common:** provide replacement for AngularJS $location service ([#30055](https://github.com/angular/angular/issues/30055)) ([4277600](https://github.com/angular/angular/commit/4277600))
* remove deprecated `DOCUMENT` token from platform-browser ([#28117](https://github.com/angular/angular/issues/28117)) ([3a9d247](https://github.com/angular/angular/commit/3a9d247)) * remove deprecated DOCUMENT token from platform-browser ([#28117](https://github.com/angular/angular/issues/28117)) ([3a9d247](https://github.com/angular/angular/commit/3a9d247))
* **compiler:** support skipping leading trivia in template source-maps ([#30095](https://github.com/angular/angular/issues/30095)) ([304a12f](https://github.com/angular/angular/commit/304a12f)) * **compiler:** support skipping leading trivia in template source-maps ([#30095](https://github.com/angular/angular/issues/30095)) ([304a12f](https://github.com/angular/angular/commit/304a12f))
* **core:** add missing ARIA attributes to html sanitizer ([#29685](https://github.com/angular/angular/issues/29685)) ([909557d](https://github.com/angular/angular/commit/909557d)), closes [#26815](https://github.com/angular/angular/issues/26815) * **core:** add missing ARIA attributes to html sanitizer ([#29685](https://github.com/angular/angular/issues/29685)) ([909557d](https://github.com/angular/angular/commit/909557d)), closes [#26815](https://github.com/angular/angular/issues/26815)
* **router:** deprecate loadChildren:string ([#30073](https://github.com/angular/angular/issues/30073)) ([c61df39](https://github.com/angular/angular/commit/c61df39)) * **router:** deprecate loadChildren:string ([#30073](https://github.com/angular/angular/issues/30073)) ([c61df39](https://github.com/angular/angular/commit/c61df39))
@ -217,28 +63,28 @@
* **service-worker:** support bypassing SW with specific header/query param ([#30010](https://github.com/angular/angular/issues/30010)) ([6200732](https://github.com/angular/angular/commit/6200732)), closes [#21191](https://github.com/angular/angular/issues/21191) * **service-worker:** support bypassing SW with specific header/query param ([#30010](https://github.com/angular/angular/issues/30010)) ([6200732](https://github.com/angular/angular/commit/6200732)), closes [#21191](https://github.com/angular/angular/issues/21191)
* **compiler-cli:** export tooling definitions ([#29929](https://github.com/angular/angular/issues/29929)) ([e1f51ea](https://github.com/angular/angular/commit/e1f51ea)) * **compiler-cli:** export tooling definitions ([#29929](https://github.com/angular/angular/issues/29929)) ([e1f51ea](https://github.com/angular/angular/commit/e1f51ea))
* **compiler-cli:** lower some exported expressions ([#30038](https://github.com/angular/angular/issues/30038)) ([8e73f9b](https://github.com/angular/angular/commit/8e73f9b)) * **compiler-cli:** lower some exported expressions ([#30038](https://github.com/angular/angular/issues/30038)) ([8e73f9b](https://github.com/angular/angular/commit/8e73f9b))
* **core:** add schematics to move deprecated `DOCUMENT` import ([#29950](https://github.com/angular/angular/issues/29950)) ([645e305](https://github.com/angular/angular/commit/645e305)) * **core:** add schematics to move deprecated DOCUMENT import ([#29950](https://github.com/angular/angular/issues/29950)) ([645e305](https://github.com/angular/angular/commit/645e305))
* **bazel:** update the build to use the new architect api ([#29720](https://github.com/angular/angular/issues/29720)) ([902a53a](https://github.com/angular/angular/commit/902a53a)) * **bazel:** update the build to use the new architect api ([#29720](https://github.com/angular/angular/issues/29720)) ([902a53a](https://github.com/angular/angular/commit/902a53a))
* remove @angular/http dependency from @angular/platform-server ([#29408](https://github.com/angular/angular/issues/29408)) ([9745f55](https://github.com/angular/angular/commit/9745f55)) * remove [@angular](https://github.com/angular)/http dependency from [@angular](https://github.com/angular)/platform-server ([#29408](https://github.com/angular/angular/issues/29408)) ([9745f55](https://github.com/angular/angular/commit/9745f55))
* **compiler-cli:** ngcc - make logging more configurable ([#29591](https://github.com/angular/angular/issues/29591)) ([8d3d75e](https://github.com/angular/angular/commit/8d3d75e)) * **compiler-cli:** ngcc - make logging more configurable ([#29591](https://github.com/angular/angular/issues/29591)) ([8d3d75e](https://github.com/angular/angular/commit/8d3d75e))
* **core:** Add `AbstractType<T>` interface ([#29295](https://github.com/angular/angular/issues/29295)) ([afd4a4e](https://github.com/angular/angular/commit/afd4a4e)), closes [#26491](https://github.com/angular/angular/issues/26491) * **core:** Add "AbstractType<T>" interface ([#29295](https://github.com/angular/angular/issues/29295)) ([afd4a4e](https://github.com/angular/angular/commit/afd4a4e)), closes [#26491](https://github.com/angular/angular/issues/26491)
* **core:** template-var-assignment update schematic ([#29608](https://github.com/angular/angular/issues/29608)) ([7c8f4e3](https://github.com/angular/angular/commit/7c8f4e3)) * **core:** template-var-assignment update schematic ([#29608](https://github.com/angular/angular/issues/29608)) ([7c8f4e3](https://github.com/angular/angular/commit/7c8f4e3))
* **bazel:** Upgrade rules_nodejs and rules_sass ([#29388](https://github.com/angular/angular/issues/29388)) ([d6d081e](https://github.com/angular/angular/commit/d6d081e)) * **bazel:** Upgrade rules_nodejs and rules_sass ([#29388](https://github.com/angular/angular/issues/29388)) ([d6d081e](https://github.com/angular/angular/commit/d6d081e))
* **service-worker:** support multiple apps on different subpaths of a domain ([#27080](https://github.com/angular/angular/issues/27080)) ([e721c08](https://github.com/angular/angular/commit/e721c08)), closes [#21388](https://github.com/angular/angular/issues/21388) * **service-worker:** support multiple apps on different subpaths of a domain ([#27080](https://github.com/angular/angular/issues/27080)) ([e721c08](https://github.com/angular/angular/commit/e721c08)), closes [#21388](https://github.com/angular/angular/issues/21388)
* **bazel:** Eject Bazel ([#29167](https://github.com/angular/angular/issues/29167)) ([36a1550](https://github.com/angular/angular/commit/36a1550)) * **bazel:** Eject Bazel ([#29167](https://github.com/angular/angular/issues/29167)) ([36a1550](https://github.com/angular/angular/commit/36a1550))
* **bazel:** Hide Bazel files in Bazel builder ([#29110](https://github.com/angular/angular/issues/29110)) ([7060d90](https://github.com/angular/angular/commit/7060d90)) * **bazel:** Hide Bazel files in Bazel builder ([#29110](https://github.com/angular/angular/issues/29110)) ([7060d90](https://github.com/angular/angular/commit/7060d90))
* **forms:** clear (remove all) components from a FormArray ([#28918](https://github.com/angular/angular/issues/28918)) ([a68b1a1](https://github.com/angular/angular/commit/a68b1a1)), closes [#18531](https://github.com/angular/angular/issues/18531) * **forms:** clear (remove all) components from a FormArray ([#28918](https://github.com/angular/angular/issues/28918)) ([a68b1a1](https://github.com/angular/angular/commit/a68b1a1)), closes [#18531](https://github.com/angular/angular/issues/18531)
* **platform-server:** wait on returned `BEFORE_APP_SERIALIZED` promises ([#29120](https://github.com/angular/angular/issues/29120)) ([7102ea8](https://github.com/angular/angular/commit/7102ea8)) * **platform-server:** wait on returned BEFORE_APP_SERIALIZED promises ([#29120](https://github.com/angular/angular/issues/29120)) ([7102ea8](https://github.com/angular/angular/commit/7102ea8))
### Bug Fixes ### Bug Fixes
* **bazel:** allow `ts_library` interop with list-typed inputs ([#30600](https://github.com/angular/angular/issues/30600)) ([bf38df4](https://github.com/angular/angular/commit/bf38df4)) * **bazel:** allow ts_library interop with list-typed inputs ([#30600](https://github.com/angular/angular/issues/30600)) ([bf38df4](https://github.com/angular/angular/commit/bf38df4))
* **bazel:** Disable sandbox on Mac OS ([#30460](https://github.com/angular/angular/issues/30460)) ([3de26a8](https://github.com/angular/angular/commit/3de26a8)) * **bazel:** Disable sandbox on Mac OS ([#30460](https://github.com/angular/angular/issues/30460)) ([3de26a8](https://github.com/angular/angular/commit/3de26a8))
* **bazel:** ng test should run specific ts_web_test_suite ([#30526](https://github.com/angular/angular/issues/30526)) ([8bc4da8](https://github.com/angular/angular/commit/8bc4da8)) * **bazel:** ng test should run specific ts_web_test_suite ([#30526](https://github.com/angular/angular/issues/30526)) ([8bc4da8](https://github.com/angular/angular/commit/8bc4da8))
* **core:** remove deprecated `TestBed.deprecatedOverrideProvider` API ([#30576](https://github.com/angular/angular/issues/30576)) ([5a46f94](https://github.com/angular/angular/commit/5a46f94)) * **core:** remove deprecated `TestBed.deprecatedOverrideProvider` API ([#30576](https://github.com/angular/angular/issues/30576)) ([5a46f94](https://github.com/angular/angular/commit/5a46f94))
* **core:** require 'static' flag on queries in typings ([#30641](https://github.com/angular/angular/issues/30641)) ([c8af830](https://github.com/angular/angular/commit/c8af830)) * **core:** require 'static' flag on queries in typings ([#30641](https://github.com/angular/angular/issues/30641)) ([c8af830](https://github.com/angular/angular/commit/c8af830))
* **core:** temporarily remove [@deprecated](https://github.com/deprecated) jsdoc tag for a `TextBed.get` overload ([#30514](https://github.com/angular/angular/issues/30514)) ([561e01d](https://github.com/angular/angular/commit/561e01d)), closes [#29290](https://github.com/angular/angular/issues/29290) [#29905](https://github.com/angular/angular/issues/29905) * **core:** temporarily remove [@deprecated](https://github.com/deprecated) jsdoc tag for a TextBed.get overload ([#30514](https://github.com/angular/angular/issues/30514)) ([561e01d](https://github.com/angular/angular/commit/561e01d)), closes [#29290](https://github.com/angular/angular/issues/29290) [#29905](https://github.com/angular/angular/issues/29905)
* **router:** type cast correctly for IE 11 bug breaking URL Unification when comparing objects ([#30464](https://github.com/angular/angular/issues/30464)) ([32daa93](https://github.com/angular/angular/commit/32daa93)) * **router:** type cast correctly for IE 11 bug breaking URL Unification when comparing objects ([#30464](https://github.com/angular/angular/issues/30464)) ([32daa93](https://github.com/angular/angular/commit/32daa93))
* **bazel:** Directly spawn native Bazel binary ([#30306](https://github.com/angular/angular/issues/30306)) ([d1fcc2b](https://github.com/angular/angular/commit/d1fcc2b)) * **bazel:** Directly spawn native Bazel binary ([#30306](https://github.com/angular/angular/issues/30306)) ([d1fcc2b](https://github.com/angular/angular/commit/d1fcc2b))
* **bazel:** pass correct arguments to http_server in Windows ([#30346](https://github.com/angular/angular/issues/30346)) ([71eba45](https://github.com/angular/angular/commit/71eba45)), closes [#29785](https://github.com/angular/angular/issues/29785) * **bazel:** pass correct arguments to http_server in Windows ([#30346](https://github.com/angular/angular/issues/30346)) ([71eba45](https://github.com/angular/angular/commit/71eba45)), closes [#29785](https://github.com/angular/angular/issues/29785)
@ -254,7 +100,7 @@
* **core:** static-query usage migration strategy should detect ambiguous query usage ([#30215](https://github.com/angular/angular/issues/30215)) ([e295c6a](https://github.com/angular/angular/commit/e295c6a)) * **core:** static-query usage migration strategy should detect ambiguous query usage ([#30215](https://github.com/angular/angular/issues/30215)) ([e295c6a](https://github.com/angular/angular/commit/e295c6a))
* **router:** ensure navigations start with the current URL value incase redirect is skipped ([#30344](https://github.com/angular/angular/issues/30344)) ([9b88920](https://github.com/angular/angular/commit/9b88920)), closes [#30340](https://github.com/angular/angular/issues/30340) [#30160](https://github.com/angular/angular/issues/30160) * **router:** ensure navigations start with the current URL value incase redirect is skipped ([#30344](https://github.com/angular/angular/issues/30344)) ([9b88920](https://github.com/angular/angular/commit/9b88920)), closes [#30340](https://github.com/angular/angular/issues/30340) [#30160](https://github.com/angular/angular/issues/30160)
* **router:** IE 11 bug can break URL unification when comparing objects ([#30393](https://github.com/angular/angular/issues/30393)) ([c383491](https://github.com/angular/angular/commit/c383491)) * **router:** IE 11 bug can break URL unification when comparing objects ([#30393](https://github.com/angular/angular/issues/30393)) ([c383491](https://github.com/angular/angular/commit/c383491))
* **bazel:** Bump ibazel to 0.10.1 for Windows fixes ([#30196](https://github.com/angular/angular/issues/30196)) ([9f68c35](https://github.com/angular/angular/commit/9f68c35)) * **bazel:** Bump ibazel to 0.10.1 for windows fixes ([#30196](https://github.com/angular/angular/issues/30196)) ([9f68c35](https://github.com/angular/angular/commit/9f68c35))
* **compiler-cli:** log ngcc skipping messages as debug instead of info ([#30232](https://github.com/angular/angular/issues/30232)) ([548b003](https://github.com/angular/angular/commit/548b003)) * **compiler-cli:** log ngcc skipping messages as debug instead of info ([#30232](https://github.com/angular/angular/issues/30232)) ([548b003](https://github.com/angular/angular/commit/548b003))
* **core:** fix interpolate identifier in AOT ([#30243](https://github.com/angular/angular/issues/30243)) ([3fe3a84](https://github.com/angular/angular/commit/3fe3a84)) * **core:** fix interpolate identifier in AOT ([#30243](https://github.com/angular/angular/issues/30243)) ([3fe3a84](https://github.com/angular/angular/commit/3fe3a84))
* **router:** ensure `history.state` is set in `eager` update mode ([#30154](https://github.com/angular/angular/issues/30154)) ([9720227](https://github.com/angular/angular/commit/9720227)) * **router:** ensure `history.state` is set in `eager` update mode ([#30154](https://github.com/angular/angular/issues/30154)) ([9720227](https://github.com/angular/angular/commit/9720227))
@ -264,54 +110,57 @@
* **bazel:** Exclude common/upgrade* in metadata.tsconfig.json ([#30133](https://github.com/angular/angular/issues/30133)) ([6711f22](https://github.com/angular/angular/commit/6711f22)) * **bazel:** Exclude common/upgrade* in metadata.tsconfig.json ([#30133](https://github.com/angular/angular/issues/30133)) ([6711f22](https://github.com/angular/angular/commit/6711f22))
* **bazel:** update peerDep ranges ([#30155](https://github.com/angular/angular/issues/30155)) ([6067583](https://github.com/angular/angular/commit/6067583)) * **bazel:** update peerDep ranges ([#30155](https://github.com/angular/angular/issues/30155)) ([6067583](https://github.com/angular/angular/commit/6067583))
* **bazel:** make name param in ng add optional ([#30074](https://github.com/angular/angular/issues/30074)) ([0b5f480](https://github.com/angular/angular/commit/0b5f480)) * **bazel:** make name param in ng add optional ([#30074](https://github.com/angular/angular/issues/30074)) ([0b5f480](https://github.com/angular/angular/commit/0b5f480))
* **bazel:** Make sure only single copy of @angular/bazel is installed ([#30072](https://github.com/angular/angular/issues/30072)) ([2905bf5](https://github.com/angular/angular/commit/2905bf5)) * **bazel:** Make sure only single copy of `[@angular](https://github.com/angular)/bazel` is installed ([#30072](https://github.com/angular/angular/issues/30072)) ([2905bf5](https://github.com/angular/angular/commit/2905bf5))
* **bazel:** transitive npm deps in ng_module ([#30065](https://github.com/angular/angular/issues/30065)) ([61365a9](https://github.com/angular/angular/commit/61365a9)) * **bazel:** transitive npm deps in ng_module ([#30065](https://github.com/angular/angular/issues/30065)) ([61365a9](https://github.com/angular/angular/commit/61365a9))
* **common:** add upgrade sub-package to `ng_package` rule for @angular/common ([#30117](https://github.com/angular/angular/issues/30117)) ([6de4cbd](https://github.com/angular/angular/commit/6de4cbd)), closes [#30055](https://github.com/angular/angular/issues/30055) [#30116](https://github.com/angular/angular/issues/30116) * **common:** add upgrade sub-package to ng_package rule for [@angular](https://github.com/angular)/common ([#30117](https://github.com/angular/angular/issues/30117)) ([6de4cbd](https://github.com/angular/angular/commit/6de4cbd)), closes [#30055](https://github.com/angular/angular/issues/30055) [#30116](https://github.com/angular/angular/issues/30116)
* **common:** adjust `MockPlatformLocation` to set state to new object ([#30055](https://github.com/angular/angular/issues/30055)) ([825efa8](https://github.com/angular/angular/commit/825efa8)) * **common:** adjust MockPlatformLocation to set state to new object ([#30055](https://github.com/angular/angular/issues/30055)) ([825efa8](https://github.com/angular/angular/commit/825efa8))
* **compiler:** Fix compiler crash due to isSkipSelf of null ([#30075](https://github.com/angular/angular/issues/30075)) ([28fd5ab](https://github.com/angular/angular/commit/28fd5ab)) * **compiler:** Fix compiler crash due to isSkipSelf of null ([#30075](https://github.com/angular/angular/issues/30075)) ([28fd5ab](https://github.com/angular/angular/commit/28fd5ab))
* **upgrade:** do not break if `onMicrotaskEmpty` emits while a `$digest` is in progress ([#29794](https://github.com/angular/angular/issues/29794)) ([0ddf2e7](https://github.com/angular/angular/commit/0ddf2e7)), closes [#24680](https://github.com/angular/angular/issues/24680) [/github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts#L12](https://github.com//github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts/issues/L12) [#24680](https://github.com/angular/angular/issues/24680) * **upgrade:** do not break if `onMicrotaskEmpty` emits while a `$digest` is in progress ([#29794](https://github.com/angular/angular/issues/29794)) ([0ddf2e7](https://github.com/angular/angular/commit/0ddf2e7)), closes [#24680](https://github.com/angular/angular/issues/24680) [/github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts#L12](https://github.com//github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts/issues/L12) [#24680](https://github.com/angular/angular/issues/24680)
* **bazel:** do not typecheck core schematic files ([#29876](https://github.com/angular/angular/issues/29876)) ([2ba799d](https://github.com/angular/angular/commit/2ba799d)) * **bazel:** do not typecheck core schematic files ([#29876](https://github.com/angular/angular/issues/29876)) ([2ba799d](https://github.com/angular/angular/commit/2ba799d))
* **bazel:** restore `ng build --prod` ([#30005](https://github.com/angular/angular/issues/30005)) ([96a8289](https://github.com/angular/angular/commit/96a8289)) * **bazel:** restore ng build --prod ([#30005](https://github.com/angular/angular/issues/30005)) ([96a8289](https://github.com/angular/angular/commit/96a8289))
* **common:** prevent repeated application of `HttpParams` mutations ([#29045](https://github.com/angular/angular/issues/29045)) ([8e8e89a](https://github.com/angular/angular/commit/8e8e89a)), closes [#20430](https://github.com/angular/angular/issues/20430) * **common:** prevent repeated application of HttpParams mutations ([#29045](https://github.com/angular/angular/issues/29045)) ([8e8e89a](https://github.com/angular/angular/commit/8e8e89a)), closes [#20430](https://github.com/angular/angular/issues/20430)
* **common:** async pipe will properly check when it receives an NaN value from an observable ([#22305](https://github.com/angular/angular/issues/22305)) ([3f6bf6d](https://github.com/angular/angular/commit/3f6bf6d)), closes [#15721](https://github.com/angular/angular/issues/15721) * **common:** async pipe will properly check when it recieves an NaN value from an observable ([#22305](https://github.com/angular/angular/issues/22305)) ([3f6bf6d](https://github.com/angular/angular/commit/3f6bf6d)), closes [#15721](https://github.com/angular/angular/issues/15721)
* **core:** don't include a local `EventListener` in typings ([#29809](https://github.com/angular/angular/issues/29809)) ([4bde40f](https://github.com/angular/angular/commit/4bde40f)), closes [#29806](https://github.com/angular/angular/issues/29806) * **core:** don't include a local `EventListener` in typings ([#29809](https://github.com/angular/angular/issues/29809)) ([4bde40f](https://github.com/angular/angular/commit/4bde40f)), closes [/github.com/angular/angular/blob/303eae918d997070a36b523ddc97e018f622c258/packages/core/src/debug/debug_node.ts#L32](https://github.com//github.com/angular/angular/blob/303eae918d997070a36b523ddc97e018f622c258/packages/core/src/debug/debug_node.ts/issues/L32) [#29806](https://github.com/angular/angular/issues/29806)
* **core:** use shakeable global definitions ([#29929](https://github.com/angular/angular/issues/29929)) ([e5905bb](https://github.com/angular/angular/commit/e5905bb)) * **core:** use shakeable global definitions ([#29929](https://github.com/angular/angular/issues/29929)) ([e5905bb](https://github.com/angular/angular/commit/e5905bb)), closes [/github.com/angular/angular-cli/blob/5fc1f2499cbe57f9a95e4b0dfced130eb3a8046d/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts#L279-L282](https://github.com//github.com/angular/angular-cli/blob/5fc1f2499cbe57f9a95e4b0dfced130eb3a8046d/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts/issues/L279-L282)
* **language-service:** Use proper types instead of any ([#29942](https://github.com/angular/angular/issues/29942)) ([1a56cd5](https://github.com/angular/angular/commit/1a56cd5)) * **language-service:** Use proper types instead of any ([#29942](https://github.com/angular/angular/issues/29942)) ([1a56cd5](https://github.com/angular/angular/commit/1a56cd5))
* **bazel:** Install packages after `ng add` when invoked independently ([#29852](https://github.com/angular/angular/issues/29852)) ([bd2ce9c](https://github.com/angular/angular/commit/bd2ce9c)) * **bazel:** Install packages after `ng add` when invoked independently ([#29852](https://github.com/angular/angular/issues/29852)) ([bd2ce9c](https://github.com/angular/angular/commit/bd2ce9c))
* **compiler-cli:** pass config path to `ts.parseJsonConfigFileContent` ([#29872](https://github.com/angular/angular/issues/29872)) ([86a3f90](https://github.com/angular/angular/commit/86a3f90)) * **compiler-cli:** pass config path to ts.parseJsonConfigFileContent ([#29872](https://github.com/angular/angular/issues/29872)) ([86a3f90](https://github.com/angular/angular/commit/86a3f90)), closes [/github.com/Microsoft/TypeScript/blob/025d82633915b67003ea38ba40b9239a19721c13/src/compiler/emitter.ts#L56-L57](https://github.com//github.com/Microsoft/TypeScript/blob/025d82633915b67003ea38ba40b9239a19721c13/src/compiler/emitter.ts/issues/L56-L57)
* **router:** support non-NgFactory promise in loadChildren typings ([#29832](https://github.com/angular/angular/issues/29832)) ([2bfb6a0](https://github.com/angular/angular/commit/2bfb6a0)) * **router:** support non-NgFactory promise in loadChildren typings ([#29832](https://github.com/angular/angular/issues/29832)) ([2bfb6a0](https://github.com/angular/angular/commit/2bfb6a0))
* **bazel:** add `configuration_env_vars = ["compile"]` to generated `@npm//@angular/bazel/bin:ngc-wrapped` `nodejs_binary` ([#29694](https://github.com/angular/angular/issues/29694)) ([2e66ddf](https://github.com/angular/angular/commit/2e66ddf)) * **bazel:** add configuration_env_vars = ["compile"] to generated [@npm](https://github.com/npm)//[@angular](https://github.com/angular)/bazel/bin:ngc-wrapped nodejs_binary ([#29694](https://github.com/angular/angular/issues/29694)) ([2e66ddf](https://github.com/angular/angular/commit/2e66ddf))
* **bazel:** docs formatting ([#29817](https://github.com/angular/angular/issues/29817)) ([cc2e4b6](https://github.com/angular/angular/commit/cc2e4b6)) * **bazel:** docs formatting ([#29817](https://github.com/angular/angular/issues/29817)) ([cc2e4b6](https://github.com/angular/angular/commit/cc2e4b6))
* **bazel:** remove karma-jasmine from `ts_web_test_suite` ([#29695](https://github.com/angular/angular/issues/29695)) ([2bd9214](https://github.com/angular/angular/commit/2bd9214)) * **bazel:** remove karma-jasmine from ts_web_test_suite ([#29695](https://github.com/angular/angular/issues/29695)) ([2bd9214](https://github.com/angular/angular/commit/2bd9214))
* **bazel:** support running ng-add on minimal applications ([#29681](https://github.com/angular/angular/issues/29681)) ([9810c6c](https://github.com/angular/angular/commit/9810c6c)), closes [#29680](https://github.com/angular/angular/issues/29680) * **bazel:** support running ng-add on minimal applications ([#29681](https://github.com/angular/angular/issues/29681)) ([9810c6c](https://github.com/angular/angular/commit/9810c6c)), closes [#29680](https://github.com/angular/angular/issues/29680)
* **common:** add `@Injectable()` to common pipes ([#29834](https://github.com/angular/angular/issues/29834)) ([387fbb8](https://github.com/angular/angular/commit/387fbb8)) * **common:** add `@Injectable()` to common pipes ([#29834](https://github.com/angular/angular/issues/29834)) ([387fbb8](https://github.com/angular/angular/commit/387fbb8))
* **compiler-cli:** ensure `LogicalProjectPaths` always start with a slash ([#29627](https://github.com/angular/angular/issues/29627)) ([e02684e](https://github.com/angular/angular/commit/e02684e)) * **compiler-cli:** ensure LogicalProjectPaths always start with a slash ([#29627](https://github.com/angular/angular/issues/29627)) ([e02684e](https://github.com/angular/angular/commit/e02684e))
* **core:** add missing migration to npm package ([#29705](https://github.com/angular/angular/issues/29705)) ([96b76dc](https://github.com/angular/angular/commit/96b76dc)) * **core:** add missing migration to npm package ([#29705](https://github.com/angular/angular/issues/29705)) ([96b76dc](https://github.com/angular/angular/commit/96b76dc))
* **core:** call `ngOnDestroy` for tree-shakeable providers ([#28943](https://github.com/angular/angular/issues/28943)) ([30b0442](https://github.com/angular/angular/commit/30b0442)), closes [#28927](https://github.com/angular/angular/issues/28927) * **core:** call ngOnDestroy for tree-shakeable providers ([#28943](https://github.com/angular/angular/issues/28943)) ([30b0442](https://github.com/angular/angular/commit/30b0442)), closes [#28927](https://github.com/angular/angular/issues/28927)
* **core:** Deprecate `TestBed.get(...):any` ([#29290](https://github.com/angular/angular/issues/29290)) ([609024f](https://github.com/angular/angular/commit/609024f)), closes [#13785](https://github.com/angular/angular/issues/13785) [#26491](https://github.com/angular/angular/issues/26491) * **core:** Deprecate TestBed.get(...):any ([#29290](https://github.com/angular/angular/issues/29290)) ([609024f](https://github.com/angular/angular/commit/609024f)), closes [#13785](https://github.com/angular/angular/issues/13785) [#26491](https://github.com/angular/angular/issues/26491)
* **core:** resolve ts compile issues due to lenient tsconfig ([#29843](https://github.com/angular/angular/issues/29843)) ([54058ba](https://github.com/angular/angular/commit/54058ba)) * **core:** resolve ts compile issues due to lenient tsconfig ([#29843](https://github.com/angular/angular/issues/29843)) ([54058ba](https://github.com/angular/angular/commit/54058ba))
* **platform-browser:** insert `APP_ID` in styles, contentAttr and hostAttr ([#17745](https://github.com/angular/angular/issues/17745)) ([712d60e](https://github.com/angular/angular/commit/712d60e)) * **platform-browser:** insert APP_ID in styles, contentAttr and hostAttr ([#17745](https://github.com/angular/angular/issues/17745)) ([712d60e](https://github.com/angular/angular/commit/712d60e))
* **bazel:** use //:tsconfig.json as the default for ng_module ([#29670](https://github.com/angular/angular/issues/29670)) ([#29711](https://github.com/angular/angular/issues/29711)) ([9e33dc3](https://github.com/angular/angular/commit/9e33dc3))
* **platform-browser:** insert APP_ID in styles, contentAttr and hostAttr ([#17745](https://github.com/angular/angular/issues/17745)) ([ca14509](https://github.com/angular/angular/commit/ca14509))
* **bazel:** Update schematics to support routing ([#29548](https://github.com/angular/angular/issues/29548)) ([401b8ee](https://github.com/angular/angular/commit/401b8ee)) * **bazel:** Update schematics to support routing ([#29548](https://github.com/angular/angular/issues/29548)) ([401b8ee](https://github.com/angular/angular/commit/401b8ee))
* **bazel:** use `//:tsconfig.json` as the default for `ng_module` ([#29670](https://github.com/angular/angular/issues/29670)) ([b14537a](https://github.com/angular/angular/commit/b14537a)) * **bazel:** use //:tsconfig.json as the default for ng_module ([#29670](https://github.com/angular/angular/issues/29670)) ([b14537a](https://github.com/angular/angular/commit/b14537a))
* **compiler-cli:** ngcc - cope with processing entry-points multiple times ([#29657](https://github.com/angular/angular/issues/29657)) ([6b39c9c](https://github.com/angular/angular/commit/6b39c9c)) * **compiler-cli:** ngcc - cope with processing entry-points multiple times ([#29657](https://github.com/angular/angular/issues/29657)) ([6b39c9c](https://github.com/angular/angular/commit/6b39c9c))
* **core:** static-query schematic should detect static queries in getters. ([#29609](https://github.com/angular/angular/issues/29609)) ([33016b8](https://github.com/angular/angular/commit/33016b8)) * **core:** static-query schematic should detect static queries in getters. ([#29609](https://github.com/angular/angular/issues/29609)) ([33016b8](https://github.com/angular/angular/commit/33016b8))
* **common:** escape query selector used when anchor scrolling ([#29577](https://github.com/angular/angular/issues/29577)) ([7671c73](https://github.com/angular/angular/commit/7671c73)), closes [#28193](https://github.com/angular/angular/issues/28193) * **common:** escape query selector used when anchor scrolling ([#29577](https://github.com/angular/angular/issues/29577)) ([7671c73](https://github.com/angular/angular/commit/7671c73)), closes [#28193](https://github.com/angular/angular/issues/28193)
* **router:** adjust setting navigationTransition when a new navigation cancels an existing one ([#29636](https://github.com/angular/angular/issues/29636)) ([e884c0c](https://github.com/angular/angular/commit/e884c0c)), closes [#29389](https://github.com/angular/angular/issues/29389) [#29590](https://github.com/angular/angular/issues/29590) * **router:** adjust setting navigationTransition when a new navigation cancels an existing one ([#29636](https://github.com/angular/angular/issues/29636)) ([e884c0c](https://github.com/angular/angular/commit/e884c0c)), closes [#29389](https://github.com/angular/angular/issues/29389) [#29590](https://github.com/angular/angular/issues/29590)
* **bazel:** allow `ng_module` users to set `createExternalSymbolFactoryReexports` ([#29459](https://github.com/angular/angular/issues/29459)) ([21be0fb](https://github.com/angular/angular/commit/21be0fb)) * **bazel:** allow ng_module users to set createExternalSymbolFactoryReexports ([#29459](https://github.com/angular/angular/issues/29459)) ([21be0fb](https://github.com/angular/angular/commit/21be0fb))
* **bazel:** workaround problem reading summary files from node_modules ([#29459](https://github.com/angular/angular/issues/29459)) ([769d960](https://github.com/angular/angular/commit/769d960)) * **bazel:** workaround problem reading summary files from node_modules ([#29459](https://github.com/angular/angular/issues/29459)) ([769d960](https://github.com/angular/angular/commit/769d960))
* **compiler:** inherit param types when class has a constructor which takes no declared parameters and delegates up ([#29232](https://github.com/angular/angular/issues/29232)) ([0007564](https://github.com/angular/angular/commit/0007564)) * **compiler:** inherit param types when class has a constructor which takes no declared parameters and delegates up ([#29232](https://github.com/angular/angular/issues/29232)) ([0007564](https://github.com/angular/angular/commit/0007564))
* **core:** parse incorrect ML open tag as text ([#29328](https://github.com/angular/angular/issues/29328)) ([dafbbf8](https://github.com/angular/angular/commit/dafbbf8)), closes [#29231](https://github.com/angular/angular/issues/29231) * **core:** parse incorrect ML open tag as text ([#29328](https://github.com/angular/angular/issues/29328)) ([dafbbf8](https://github.com/angular/angular/commit/dafbbf8)), closes [#29231](https://github.com/angular/angular/issues/29231)
* **core:** static-query schematic should detect queries in `ngDoCheck` and `ngOnChanges` ([#29492](https://github.com/angular/angular/issues/29492)) ([09fab58](https://github.com/angular/angular/commit/09fab58)) * **core:** static-query schematic should detect queries in "ngDoCheck" and "ngOnChanges" ([#29492](https://github.com/angular/angular/issues/29492)) ([09fab58](https://github.com/angular/angular/commit/09fab58))
* **router:** support `NgFactory` promise in loadChildren typings ([#29392](https://github.com/angular/angular/issues/29392)) ([26a8c59](https://github.com/angular/angular/commit/26a8c59)) * **router:** support NgFactory promise in loadChildren typings ([#29392](https://github.com/angular/angular/issues/29392)) ([26a8c59](https://github.com/angular/angular/commit/26a8c59))
* **bazel:** correct regexp test for self-references in metadata ([#29346](https://github.com/angular/angular/issues/29346)) ([9d090cb](https://github.com/angular/angular/commit/9d090cb)) * **bazel:** correct regexp test for self-references in metadata ([#29346](https://github.com/angular/angular/issues/29346)) ([9d090cb](https://github.com/angular/angular/commit/9d090cb))
* **bazel:** don't produce self-references in metadata ([#29317](https://github.com/angular/angular/issues/29317)) ([3facdeb](https://github.com/angular/angular/commit/3facdeb)), closes [#29315](https://github.com/angular/angular/issues/29315) * **bazel:** don't produce self-references in metadata ([#29317](https://github.com/angular/angular/issues/29317)) ([3facdeb](https://github.com/angular/angular/commit/3facdeb)), closes [#29315](https://github.com/angular/angular/issues/29315)
* **bazel:** fix strict null checks compile error in `packages/bazel/src/schematics/ng-add/index.ts` ([#29282](https://github.com/angular/angular/issues/29282)) ([9a7f560](https://github.com/angular/angular/commit/9a7f560)) * **bazel:** fix strict null checks compile error in packages/bazel/src/schematics/ng-add/index.ts ([#29282](https://github.com/angular/angular/issues/29282)) ([9a7f560](https://github.com/angular/angular/commit/9a7f560))
* **bazel:** Remove @angular/upgrade from dev dependencies ([#29319](https://github.com/angular/angular/issues/29319)) ([1db8bf3](https://github.com/angular/angular/commit/1db8bf3)) * **bazel:** Remove [@angular](https://github.com/angular)/upgrade from dev dependencies ([#29319](https://github.com/angular/angular/issues/29319)) ([1db8bf3](https://github.com/angular/angular/commit/1db8bf3))
* **bazel:** Support new e2e project layout ([#29318](https://github.com/angular/angular/issues/29318)) ([8ef690c](https://github.com/angular/angular/commit/8ef690c)) * **bazel:** Support new e2e project layout ([#29318](https://github.com/angular/angular/issues/29318)) ([8ef690c](https://github.com/angular/angular/commit/8ef690c))
* **bazel:** turn off pure call tree shaking for ng_package ([#29210](https://github.com/angular/angular/issues/29210)) ([4990b93](https://github.com/angular/angular/commit/4990b93)) * **bazel:** turn off pure call tree shaking for ng_package ([#29210](https://github.com/angular/angular/issues/29210)) ([4990b93](https://github.com/angular/angular/commit/4990b93))
* **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([105cfaf](https://github.com/angular/angular/commit/105cfaf)) * **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([105cfaf](https://github.com/angular/angular/commit/105cfaf)), closes [/github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85](https://github.com//github.com/angular/material2/blob/master/tools/package-tools/build-release.ts/issues/L78-L85)
* **core:** don't wrap `<tr>` and `<col>` elements into a required parent ([#29219](https://github.com/angular/angular/issues/29219)) ([f2dc32e](https://github.com/angular/angular/commit/f2dc32e)) * **core:** don't wrap `<tr>` and `<col>` elements into a required parent ([#29219](https://github.com/angular/angular/issues/29219)) ([f2dc32e](https://github.com/angular/angular/commit/f2dc32e))
* **core:** parse incorrect ML open tag as text ([#29328](https://github.com/angular/angular/issues/29328)) ([4605df8](https://github.com/angular/angular/commit/4605df8)), closes [#29231](https://github.com/angular/angular/issues/29231) * **core:** parse incorrect ML open tag as text ([#29328](https://github.com/angular/angular/issues/29328)) ([4605df8](https://github.com/angular/angular/commit/4605df8)), closes [#29231](https://github.com/angular/angular/issues/29231)
* **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([cf8d934](https://github.com/angular/angular/commit/cf8d934)), closes [github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85](https://github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85)
* **bazel:** add missing binary path for api-extractor ([#29202](https://github.com/angular/angular/issues/29202)) ([df354d1](https://github.com/angular/angular/commit/df354d1)) * **bazel:** add missing binary path for api-extractor ([#29202](https://github.com/angular/angular/issues/29202)) ([df354d1](https://github.com/angular/angular/commit/df354d1))
* **bazel:** ng build should produce prod bundle ([#29136](https://github.com/angular/angular/issues/29136)) ([14ce8a9](https://github.com/angular/angular/commit/14ce8a9)) * **bazel:** ng build should produce prod bundle ([#29136](https://github.com/angular/angular/issues/29136)) ([14ce8a9](https://github.com/angular/angular/commit/14ce8a9))
* **compiler:** ensure template is updated if an output is transformed ([#29041](https://github.com/angular/angular/issues/29041)) ([c7e4931](https://github.com/angular/angular/commit/c7e4931)) * **compiler:** ensure template is updated if an output is transformed ([#29041](https://github.com/angular/angular/issues/29041)) ([c7e4931](https://github.com/angular/angular/commit/c7e4931))
@ -325,16 +174,16 @@
### BREAKING CHANGES ### BREAKING CHANGES
* **bazel:** @bazel/typescript is now a peerDependency of @angular/bazel so users of @angular/bazel must add @bazel/typescript to their package.json * **bazel:** @bazel/typescript is now a peerDependency of @angular/bazel so user's of @angular/bazel must add @bazel/typescript to their package.json
* **bazel:** `ng_module` now depends on a minimum of build_bazel_rules_nodejs 0.27.12 * **bazel:** ng_module now depends on a minimum of build_bazel_rules_nodejs 0.27.12
* **core:** In Angular version 8, it's required that all `@ViewChild` and `@ContentChild` * **core:** In Angular version 8, it's required that all @ViewChild and @ContentChild
queries have a `'static'` flag specifying whether the query is 'static' or queries have a 'static' flag specifying whether the query is 'static' or
'dynamic'. The compiler previously sorted queries automatically, but in 'dynamic'. The compiler previously sorted queries automatically, but in
8.0 developers are required to explicitly specify which behavior is wanted. 8.0 developers are required to explicitly specify which behavior is wanted.
This is a temporary requirement as part of a migration; see This is a temporary requirement as part of a migration; see
[static query migration guide](https://v8.angular.io/guide/static-query-migration) for more details. https://v8.angular.io/guide/static-query-migration for more details.
`@ViewChildren` and `@ContentChildren` queries are always dynamic, and so are @ViewChildren and @ContentChildren queries are always dynamic, and so are
unaffected. unaffected.
* `TestBed.get()` has two signatures, one which is typed and another which accepts and returns `any`. The signature for `any` is deprecated; all usage of `TestBed.get()` should go through the typed API. This mainly affects string tokens * `TestBed.get()` has two signatures, one which is typed and another which accepts and returns `any`. The signature for `any` is deprecated; all usage of `TestBed.get()` should go through the typed API. This mainly affects string tokens
@ -368,8 +217,8 @@ This is a temporary requirement as part of a migration; see
- `<tr>` would be wrapped in `<tbody>` if not inside `<tbody>`, `<tfoot>` or `<thead>`; - `<tr>` would be wrapped in `<tbody>` if not inside `<tbody>`, `<tfoot>` or `<thead>`;
- `<col>` would be wrapped in `<colgroup>` if not inside `<colgroup>`. - `<col>` would be wrapped in `<colgroup>` if not inside `<colgroup>`.
This mechanism of automatic wrapping / auto-correcting was problematic for several reasons: This meachanism of automatic wrapping / auto-correcting was problematic for several reasons:
- it is non-obvious and arbitrary (ex. there are more HTML elements that have rules for parent type); - it is non-obvious and arbitrary (ex. there are more HTML elements that has rules for parent type);
- it is incorrect for cases where `<tr>` / `<col>` are at the root of a component's content, ex.: - it is incorrect for cases where `<tr>` / `<col>` are at the root of a component's content, ex.:
```html ```html
@ -381,13 +230,10 @@ This is a temporary requirement as part of a migration; see
In the above example the `<projecting-tr-inside-tbody>` component could be "surprised" to see additional In the above example the `<projecting-tr-inside-tbody>` component could be "surprised" to see additional
`<tbody>` elements inserted by Angular HTML parser. `<tbody>` elements inserted by Angular HTML parser.
* **http:** The deprecated @angular/http package has been removed, the @angular/common/http package should be used instead.
For details on how to migrate, please refer to [the deprecations guide](https://angular.io/guide/deprecations#angularhttp).
* TypeScript 3.1 and 3.2 are no longer supported. * TypeScript 3.1 and 3.2 are no longer supported.
Please update your TypeScript version to 3.4, as version 3.3 is also not supported. Please update your TypeScript version to 3.3
<a name="8.0.0-rc.5"></a> <a name="8.0.0-rc.5"></a>
@ -473,17 +319,6 @@ unaffected.
<a name="7.2.15"></a>
## [7.2.15](https://github.com/angular/angular/compare/7.2.14...7.2.15) (2019-05-07)
### Bug Fixes
* **upgrade:** do not break if `onMicrotaskEmpty` emits while a `$digest` is in progress ([#29794](https://github.com/angular/angular/issues/29794)) ([#30107](https://github.com/angular/angular/issues/30107)) ([1084c19](https://github.com/angular/angular/commit/1084c19)), closes [#24680](https://github.com/angular/angular/issues/24680) [/github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts#L12](https://github.com//github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts/issues/L12) [#24680](https://github.com/angular/angular/issues/24680)
<a name="8.0.0-rc.2"></a> <a name="8.0.0-rc.2"></a>
# [8.0.0-rc.2](https://github.com/angular/angular/compare/8.0.0-rc.1...8.0.0-rc.2) (2019-04-29) # [8.0.0-rc.2](https://github.com/angular/angular/compare/8.0.0-rc.1...8.0.0-rc.2) (2019-04-29)
@ -513,9 +348,9 @@ unaffected.
### Bug Fixes ### Bug Fixes
* **bazel:** make name param in ng add optional ([#30074](https://github.com/angular/angular/issues/30074)) ([0b5f480](https://github.com/angular/angular/commit/0b5f480)) * **bazel:** make name param in ng add optional ([#30074](https://github.com/angular/angular/issues/30074)) ([0b5f480](https://github.com/angular/angular/commit/0b5f480))
* **bazel:** Make sure only single copy of `@angular/bazel` is installed ([#30072](https://github.com/angular/angular/issues/30072)) ([2905bf5](https://github.com/angular/angular/commit/2905bf5)) * **bazel:** Make sure only single copy of `[@angular](https://github.com/angular)/bazel` is installed ([#30072](https://github.com/angular/angular/issues/30072)) ([2905bf5](https://github.com/angular/angular/commit/2905bf5))
* **bazel:** transitive npm deps in ng_module ([#30065](https://github.com/angular/angular/issues/30065)) ([61365a9](https://github.com/angular/angular/commit/61365a9)) * **bazel:** transitive npm deps in ng_module ([#30065](https://github.com/angular/angular/issues/30065)) ([61365a9](https://github.com/angular/angular/commit/61365a9))
* **common:** add upgrade sub-package to ng_package rule for @angular/common ([#30117](https://github.com/angular/angular/issues/30117)) ([6de4cbd](https://github.com/angular/angular/commit/6de4cbd)), closes [#30055](https://github.com/angular/angular/issues/30055) [#30116](https://github.com/angular/angular/issues/30116) * **common:** add upgrade sub-package to ng_package rule for [@angular](https://github.com/angular)/common ([#30117](https://github.com/angular/angular/issues/30117)) ([6de4cbd](https://github.com/angular/angular/commit/6de4cbd)), closes [#30055](https://github.com/angular/angular/issues/30055) [#30116](https://github.com/angular/angular/issues/30116)
* **common:** adjust MockPlatformLocation to set state to new object ([#30055](https://github.com/angular/angular/issues/30055)) ([825efa8](https://github.com/angular/angular/commit/825efa8)) * **common:** adjust MockPlatformLocation to set state to new object ([#30055](https://github.com/angular/angular/issues/30055)) ([825efa8](https://github.com/angular/angular/commit/825efa8))
* **compiler:** Fix compiler crash due to isSkipSelf of null ([#30075](https://github.com/angular/angular/issues/30075)) ([28fd5ab](https://github.com/angular/angular/commit/28fd5ab)) * **compiler:** Fix compiler crash due to isSkipSelf of null ([#30075](https://github.com/angular/angular/issues/30075)) ([28fd5ab](https://github.com/angular/angular/commit/28fd5ab))
* **upgrade:** do not break if `onMicrotaskEmpty` emits while a `$digest` is in progress ([#29794](https://github.com/angular/angular/issues/29794)) ([0ddf2e7](https://github.com/angular/angular/commit/0ddf2e7)), closes [#24680](https://github.com/angular/angular/issues/24680) [/github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts#L12](https://github.com//github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts/issues/L12) [#24680](https://github.com/angular/angular/issues/24680) * **upgrade:** do not break if `onMicrotaskEmpty` emits while a `$digest` is in progress ([#29794](https://github.com/angular/angular/issues/29794)) ([0ddf2e7](https://github.com/angular/angular/commit/0ddf2e7)), closes [#24680](https://github.com/angular/angular/issues/24680) [/github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts#L12](https://github.com//github.com/angular/angular/blob/78146c189/packages/core/src/util/ng_dev_mode.ts/issues/L12) [#24680](https://github.com/angular/angular/issues/24680)
@ -523,7 +358,7 @@ unaffected.
### Features ### Features
* **common:** add @angular/common/upgrade package for $location-related APIs ([#30055](https://github.com/angular/angular/issues/30055)) ([152d99e](https://github.com/angular/angular/commit/152d99e)) * **common:** add [@angular](https://github.com/angular)/common/upgrade package for $location-related APIs ([#30055](https://github.com/angular/angular/issues/30055)) ([152d99e](https://github.com/angular/angular/commit/152d99e))
* **common:** add ability to retrieve the state from Location service ([#30055](https://github.com/angular/angular/issues/30055)) ([b44b143](https://github.com/angular/angular/commit/b44b143)) * **common:** add ability to retrieve the state from Location service ([#30055](https://github.com/angular/angular/issues/30055)) ([b44b143](https://github.com/angular/angular/commit/b44b143))
* **common:** add ability to track all location changes ([#30055](https://github.com/angular/angular/issues/30055)) ([3a9cf3f](https://github.com/angular/angular/commit/3a9cf3f)) * **common:** add ability to track all location changes ([#30055](https://github.com/angular/angular/issues/30055)) ([3a9cf3f](https://github.com/angular/angular/commit/3a9cf3f))
* **common:** add APIs to read component pieces of URL ([#30055](https://github.com/angular/angular/issues/30055)) ([b635fe8](https://github.com/angular/angular/commit/b635fe8)) * **common:** add APIs to read component pieces of URL ([#30055](https://github.com/angular/angular/issues/30055)) ([b635fe8](https://github.com/angular/angular/commit/b635fe8))
@ -586,7 +421,7 @@ unaffected.
### Bug Fixes ### Bug Fixes
* **bazel:** add configuration_env_vars = ["compile"] to generated [@npm](https://github.com/npm)//@angular/bazel/bin:ngc-wrapped nodejs_binary ([#29694](https://github.com/angular/angular/issues/29694)) ([2e66ddf](https://github.com/angular/angular/commit/2e66ddf)) * **bazel:** add configuration_env_vars = ["compile"] to generated [@npm](https://github.com/npm)//[@angular](https://github.com/angular)/bazel/bin:ngc-wrapped nodejs_binary ([#29694](https://github.com/angular/angular/issues/29694)) ([2e66ddf](https://github.com/angular/angular/commit/2e66ddf))
* **bazel:** docs formatting ([#29817](https://github.com/angular/angular/issues/29817)) ([cc2e4b6](https://github.com/angular/angular/commit/cc2e4b6)) * **bazel:** docs formatting ([#29817](https://github.com/angular/angular/issues/29817)) ([cc2e4b6](https://github.com/angular/angular/commit/cc2e4b6))
* **bazel:** remove karma-jasmine from ts_web_test_suite ([#29695](https://github.com/angular/angular/issues/29695)) ([2bd9214](https://github.com/angular/angular/commit/2bd9214)) * **bazel:** remove karma-jasmine from ts_web_test_suite ([#29695](https://github.com/angular/angular/issues/29695)) ([2bd9214](https://github.com/angular/angular/commit/2bd9214))
* **bazel:** support running ng-add on minimal applications ([#29681](https://github.com/angular/angular/issues/29681)) ([9810c6c](https://github.com/angular/angular/commit/9810c6c)), closes [#29680](https://github.com/angular/angular/issues/29680) * **bazel:** support running ng-add on minimal applications ([#29681](https://github.com/angular/angular/issues/29681)) ([9810c6c](https://github.com/angular/angular/commit/9810c6c)), closes [#29680](https://github.com/angular/angular/issues/29680)
@ -661,7 +496,7 @@ let service = TestBed.get(SERVICE_TOKEN); // type Service
### Features ### Features
* remove @angular/http dependency from @angular/platform-server ([#29408](https://github.com/angular/angular/issues/29408)) ([9745f55](https://github.com/angular/angular/commit/9745f55)) * remove [@angular](https://github.com/angular)/http dependency from [@angular](https://github.com/angular)/platform-server ([#29408](https://github.com/angular/angular/issues/29408)) ([9745f55](https://github.com/angular/angular/commit/9745f55))
* **compiler-cli:** ngcc - make logging more configurable ([#29591](https://github.com/angular/angular/issues/29591)) ([8d3d75e](https://github.com/angular/angular/commit/8d3d75e)) * **compiler-cli:** ngcc - make logging more configurable ([#29591](https://github.com/angular/angular/issues/29591)) ([8d3d75e](https://github.com/angular/angular/commit/8d3d75e))
* **core:** Add "AbstractType<T>" interface ([#29295](https://github.com/angular/angular/issues/29295)) ([afd4a4e](https://github.com/angular/angular/commit/afd4a4e)), closes [#26491](https://github.com/angular/angular/issues/26491) * **core:** Add "AbstractType<T>" interface ([#29295](https://github.com/angular/angular/issues/29295)) ([afd4a4e](https://github.com/angular/angular/commit/afd4a4e)), closes [#26491](https://github.com/angular/angular/issues/26491)
* **core:** template-var-assignment update schematic ([#29608](https://github.com/angular/angular/issues/29608)) ([7c8f4e3](https://github.com/angular/angular/commit/7c8f4e3)) * **core:** template-var-assignment update schematic ([#29608](https://github.com/angular/angular/issues/29608)) ([7c8f4e3](https://github.com/angular/angular/commit/7c8f4e3))
@ -721,7 +556,7 @@ This release contains various API docs improvements.
* **bazel:** correct regexp test for self-references in metadata ([#29346](https://github.com/angular/angular/issues/29346)) ([9d090cb](https://github.com/angular/angular/commit/9d090cb)) * **bazel:** correct regexp test for self-references in metadata ([#29346](https://github.com/angular/angular/issues/29346)) ([9d090cb](https://github.com/angular/angular/commit/9d090cb))
* **bazel:** don't produce self-references in metadata ([#29317](https://github.com/angular/angular/issues/29317)) ([3facdeb](https://github.com/angular/angular/commit/3facdeb)), closes [#29315](https://github.com/angular/angular/issues/29315) * **bazel:** don't produce self-references in metadata ([#29317](https://github.com/angular/angular/issues/29317)) ([3facdeb](https://github.com/angular/angular/commit/3facdeb)), closes [#29315](https://github.com/angular/angular/issues/29315)
* **bazel:** fix strict null checks compile error in packages/bazel/src/schematics/ng-add/index.ts ([#29282](https://github.com/angular/angular/issues/29282)) ([9a7f560](https://github.com/angular/angular/commit/9a7f560)) * **bazel:** fix strict null checks compile error in packages/bazel/src/schematics/ng-add/index.ts ([#29282](https://github.com/angular/angular/issues/29282)) ([9a7f560](https://github.com/angular/angular/commit/9a7f560))
* **bazel:** Remove @angular/upgrade from dev dependencies ([#29319](https://github.com/angular/angular/issues/29319)) ([1db8bf3](https://github.com/angular/angular/commit/1db8bf3)) * **bazel:** Remove [@angular](https://github.com/angular)/upgrade from dev dependencies ([#29319](https://github.com/angular/angular/issues/29319)) ([1db8bf3](https://github.com/angular/angular/commit/1db8bf3))
* **bazel:** Support new e2e project layout ([#29318](https://github.com/angular/angular/issues/29318)) ([8ef690c](https://github.com/angular/angular/commit/8ef690c)) * **bazel:** Support new e2e project layout ([#29318](https://github.com/angular/angular/issues/29318)) ([8ef690c](https://github.com/angular/angular/commit/8ef690c))
* **bazel:** turn off pure call tree shaking for ng_package ([#29210](https://github.com/angular/angular/issues/29210)) ([4990b93](https://github.com/angular/angular/commit/4990b93)) * **bazel:** turn off pure call tree shaking for ng_package ([#29210](https://github.com/angular/angular/issues/29210)) ([4990b93](https://github.com/angular/angular/commit/4990b93))
* **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([105cfaf](https://github.com/angular/angular/commit/105cfaf)), closes [/github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85](https://github.com//github.com/angular/material2/blob/master/tools/package-tools/build-release.ts/issues/L78-L85) * **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([105cfaf](https://github.com/angular/angular/commit/105cfaf)), closes [/github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85](https://github.com//github.com/angular/material2/blob/master/tools/package-tools/build-release.ts/issues/L78-L85)
@ -742,8 +577,8 @@ This release contains various API docs improvements.
- `<tr>` would be wrapped in `<tbody>` if not inside `<tbody>`, `<tfoot>` or `<thead>`; - `<tr>` would be wrapped in `<tbody>` if not inside `<tbody>`, `<tfoot>` or `<thead>`;
- `<col>` would be wrapped in `<colgroup>` if not inside `<colgroup>`. - `<col>` would be wrapped in `<colgroup>` if not inside `<colgroup>`.
This mechanism of automatic wrapping / auto-correcting was problematic for several reasons: This meachanism of automatic wrapping / auto-correcting was problematic for several reasons:
- it is non-obvious and arbitrary (ex. there are more HTML elements that have rules for parent type); - it is non-obvious and arbitrary (ex. there are more HTML elements that has rules for parent type);
- it is incorrect for cases where `<tr>` / `<col>` are at the root of a component's content, ex.: - it is incorrect for cases where `<tr>` / `<col>` are at the root of a component's content, ex.:
```html ```html
@ -1144,7 +979,7 @@ This release contains various API docs improvements.
* **bazel:** unable to launch protractor test on windows ([#27850](https://github.com/angular/angular/issues/27850)) ([1e6c9be](https://github.com/angular/angular/commit/1e6c9be)) * **bazel:** unable to launch protractor test on windows ([#27850](https://github.com/angular/angular/issues/27850)) ([1e6c9be](https://github.com/angular/angular/commit/1e6c9be))
* **bazel:** devserver entry_module should have underscore name ([#27719](https://github.com/angular/angular/issues/27719)) ([f57916c](https://github.com/angular/angular/commit/f57916c)) * **bazel:** devserver entry_module should have underscore name ([#27719](https://github.com/angular/angular/issues/27719)) ([f57916c](https://github.com/angular/angular/commit/f57916c))
* **bazel:** emit full node stack traces when Angular compilation crashes ([#27678](https://github.com/angular/angular/issues/27678)) ([522919a](https://github.com/angular/angular/commit/522919a)) * **bazel:** emit full node stack traces when Angular compilation crashes ([#27678](https://github.com/angular/angular/issues/27678)) ([522919a](https://github.com/angular/angular/commit/522919a))
* **bazel:** fix major/minor semver check between @angular/bazel npm packager version and angular bazel repo version ([#27635](https://github.com/angular/angular/issues/27635)) ([1cc08b4](https://github.com/angular/angular/commit/1cc08b4)) * **bazel:** fix major/minor semver check between [@angular](https://github.com/angular)/bazel npm packager version and angular bazel repo version ([#27635](https://github.com/angular/angular/issues/27635)) ([1cc08b4](https://github.com/angular/angular/commit/1cc08b4))
* **bazel:** Load http_archive and rules_nodejs dependencies ([#27609](https://github.com/angular/angular/issues/27609)) ([8313ffc](https://github.com/angular/angular/commit/8313ffc)) * **bazel:** Load http_archive and rules_nodejs dependencies ([#27609](https://github.com/angular/angular/issues/27609)) ([8313ffc](https://github.com/angular/angular/commit/8313ffc))
* **bazel:** ng_package writes unrelevant definitions to bazel out ([#27519](https://github.com/angular/angular/issues/27519)) ([44dfa60](https://github.com/angular/angular/commit/44dfa60)), closes [/github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts#L105-L124](https://github.com//github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts/issues/L105-L124) * **bazel:** ng_package writes unrelevant definitions to bazel out ([#27519](https://github.com/angular/angular/issues/27519)) ([44dfa60](https://github.com/angular/angular/commit/44dfa60)), closes [/github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts#L105-L124](https://github.com//github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts/issues/L105-L124)
* **bazel:** Set module_name and enable ng test ([#27715](https://github.com/angular/angular/issues/27715)) ([85866de](https://github.com/angular/angular/commit/85866de)) * **bazel:** Set module_name and enable ng test ([#27715](https://github.com/angular/angular/issues/27715)) ([85866de](https://github.com/angular/angular/commit/85866de))
@ -1164,7 +999,7 @@ This release contains various API docs improvements.
* **core:** export a value for InjectFlags ([#27279](https://github.com/angular/angular/issues/27279)) ([23b06af](https://github.com/angular/angular/commit/23b06af)), closes [#27251](https://github.com/angular/angular/issues/27251) * **core:** export a value for InjectFlags ([#27279](https://github.com/angular/angular/issues/27279)) ([23b06af](https://github.com/angular/angular/commit/23b06af)), closes [#27251](https://github.com/angular/angular/issues/27251)
* **core:** More precise return type for `InjectableDecorator` ([#27360](https://github.com/angular/angular/issues/27360)) ([4b9948c](https://github.com/angular/angular/commit/4b9948c)), closes [#26942](https://github.com/angular/angular/issues/26942) * **core:** More precise return type for `InjectableDecorator` ([#27360](https://github.com/angular/angular/issues/27360)) ([4b9948c](https://github.com/angular/angular/commit/4b9948c)), closes [#26942](https://github.com/angular/angular/issues/26942)
* **forms:** typed argument for FormBuilder group ([#26985](https://github.com/angular/angular/issues/26985)) ([b0c7561](https://github.com/angular/angular/commit/b0c7561)) * **forms:** typed argument for FormBuilder group ([#26985](https://github.com/angular/angular/issues/26985)) ([b0c7561](https://github.com/angular/angular/commit/b0c7561))
* **platform-server:** add @angular/http to the list of peerDependencies ([#27307](https://github.com/angular/angular/issues/27307)) ([32c5be9](https://github.com/angular/angular/commit/32c5be9)), closes [#26154](https://github.com/angular/angular/issues/26154) * **platform-server:** add [@angular](https://github.com/angular)/http to the list of peerDependencies ([#27307](https://github.com/angular/angular/issues/27307)) ([32c5be9](https://github.com/angular/angular/commit/32c5be9)), closes [#26154](https://github.com/angular/angular/issues/26154)
* **router:** ensure URL is updated after second redirect with UrlUpdateStrategy="eager" ([#27523](https://github.com/angular/angular/issues/27523)) ([ad26cd6](https://github.com/angular/angular/commit/ad26cd6)), closes [#27116](https://github.com/angular/angular/issues/27116) * **router:** ensure URL is updated after second redirect with UrlUpdateStrategy="eager" ([#27523](https://github.com/angular/angular/issues/27523)) ([ad26cd6](https://github.com/angular/angular/commit/ad26cd6)), closes [#27116](https://github.com/angular/angular/issues/27116)
* **router:** update URL after redirects when urlHandlingStrategy='eager' ([#27356](https://github.com/angular/angular/issues/27356)) ([11a8bd8](https://github.com/angular/angular/commit/11a8bd8)), closes [#27076](https://github.com/angular/angular/issues/27076) * **router:** update URL after redirects when urlHandlingStrategy='eager' ([#27356](https://github.com/angular/angular/issues/27356)) ([11a8bd8](https://github.com/angular/angular/commit/11a8bd8)), closes [#27076](https://github.com/angular/angular/issues/27076)
* **upgrade:** allow nesting components from different downgraded modules ([#27217](https://github.com/angular/angular/issues/27217)) ([bc0ee01](https://github.com/angular/angular/commit/bc0ee01)) * **upgrade:** allow nesting components from different downgraded modules ([#27217](https://github.com/angular/angular/issues/27217)) ([bc0ee01](https://github.com/angular/angular/commit/bc0ee01))
@ -1184,7 +1019,7 @@ This release contains various API docs improvements.
* **animations:** mark actual descendant node as disabled ([#26180](https://github.com/angular/angular/issues/26180)) ([453589f](https://github.com/angular/angular/commit/453589f)) * **animations:** mark actual descendant node as disabled ([#26180](https://github.com/angular/angular/issues/26180)) ([453589f](https://github.com/angular/angular/commit/453589f))
* **bazel:** devserver entry_module should have underscore name ([#27719](https://github.com/angular/angular/issues/27719)) ([b108e9a](https://github.com/angular/angular/commit/b108e9a)) * **bazel:** devserver entry_module should have underscore name ([#27719](https://github.com/angular/angular/issues/27719)) ([b108e9a](https://github.com/angular/angular/commit/b108e9a))
* **bazel:** emit full node stack traces when Angular compilation crashes ([#27678](https://github.com/angular/angular/issues/27678)) ([0d8528b](https://github.com/angular/angular/commit/0d8528b)) * **bazel:** emit full node stack traces when Angular compilation crashes ([#27678](https://github.com/angular/angular/issues/27678)) ([0d8528b](https://github.com/angular/angular/commit/0d8528b))
* **bazel:** fix major/minor semver check between @angular/bazel npm packager version and angular bazel repo version ([#27635](https://github.com/angular/angular/issues/27635)) ([3ed1e84](https://github.com/angular/angular/commit/3ed1e84)) * **bazel:** fix major/minor semver check between [@angular](https://github.com/angular)/bazel npm packager version and angular bazel repo version ([#27635](https://github.com/angular/angular/issues/27635)) ([3ed1e84](https://github.com/angular/angular/commit/3ed1e84))
* **bazel:** Load http_archive and rules_nodejs dependencies ([#27609](https://github.com/angular/angular/issues/27609)) ([89ace1a](https://github.com/angular/angular/commit/89ace1a)) * **bazel:** Load http_archive and rules_nodejs dependencies ([#27609](https://github.com/angular/angular/issues/27609)) ([89ace1a](https://github.com/angular/angular/commit/89ace1a))
* **bazel:** ng_package writes unrelevant definitions to bazel out ([#27519](https://github.com/angular/angular/issues/27519)) ([ef056c5](https://github.com/angular/angular/commit/ef056c5)), closes [/github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts#L105-L124](https://github.com//github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts/issues/L105-L124) * **bazel:** ng_package writes unrelevant definitions to bazel out ([#27519](https://github.com/angular/angular/issues/27519)) ([ef056c5](https://github.com/angular/angular/commit/ef056c5)), closes [/github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts#L105-L124](https://github.com//github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts/issues/L105-L124)
* **bazel:** Read latest versions from latest-versions.ts & use semver check ([#27591](https://github.com/angular/angular/issues/27591)) ([93078e3](https://github.com/angular/angular/commit/93078e3)) * **bazel:** Read latest versions from latest-versions.ts & use semver check ([#27591](https://github.com/angular/angular/issues/27591)) ([93078e3](https://github.com/angular/angular/commit/93078e3))
@ -1216,7 +1051,7 @@ This release contains various API docs improvements.
* **bazel:** ng_package should correctly map to source maps in secondary entry-points ([#27313](https://github.com/angular/angular/issues/27313)) ([fc2c23e](https://github.com/angular/angular/commit/fc2c23e)), closes [#25510](https://github.com/angular/angular/issues/25510) * **bazel:** ng_package should correctly map to source maps in secondary entry-points ([#27313](https://github.com/angular/angular/issues/27313)) ([fc2c23e](https://github.com/angular/angular/commit/fc2c23e)), closes [#25510](https://github.com/angular/angular/issues/25510)
* **compiler-cli:** flatModuleIndex files not generated on windows with multiple input files ([#27200](https://github.com/angular/angular/issues/27200)) ([8087b6b](https://github.com/angular/angular/commit/8087b6b)) * **compiler-cli:** flatModuleIndex files not generated on windows with multiple input files ([#27200](https://github.com/angular/angular/issues/27200)) ([8087b6b](https://github.com/angular/angular/commit/8087b6b))
* **compiler-cli:** ngtsc shim files not being generated on case-insensitive platforms ([#27466](https://github.com/angular/angular/issues/27466)) ([84f2928](https://github.com/angular/angular/commit/84f2928)), closes [/github.com/Microsoft/TypeScript/blob/3e4c5c95abd515eb9713b881d27ab3a93cc00461/src/compiler/sys.ts#L681-L682](https://github.com//github.com/Microsoft/TypeScript/blob/3e4c5c95abd515eb9713b881d27ab3a93cc00461/src/compiler/sys.ts/issues/L681-L682) * **compiler-cli:** ngtsc shim files not being generated on case-insensitive platforms ([#27466](https://github.com/angular/angular/issues/27466)) ([84f2928](https://github.com/angular/angular/commit/84f2928)), closes [/github.com/Microsoft/TypeScript/blob/3e4c5c95abd515eb9713b881d27ab3a93cc00461/src/compiler/sys.ts#L681-L682](https://github.com//github.com/Microsoft/TypeScript/blob/3e4c5c95abd515eb9713b881d27ab3a93cc00461/src/compiler/sys.ts/issues/L681-L682)
* **platform-server:** add @angular/http to the list of peerDependencies ([#27307](https://github.com/angular/angular/issues/27307)) ([236ac06](https://github.com/angular/angular/commit/236ac06)), closes [#26154](https://github.com/angular/angular/issues/26154) * **platform-server:** add [@angular](https://github.com/angular)/http to the list of peerDependencies ([#27307](https://github.com/angular/angular/issues/27307)) ([236ac06](https://github.com/angular/angular/commit/236ac06)), closes [#26154](https://github.com/angular/angular/issues/26154)
@ -1243,7 +1078,7 @@ This release contains various API docs improvements.
* **compiler:** generate inputs with aliases properly ([#26774](https://github.com/angular/angular/issues/26774)) ([19fcfc3](https://github.com/angular/angular/commit/19fcfc3)) * **compiler:** generate inputs with aliases properly ([#26774](https://github.com/angular/angular/issues/26774)) ([19fcfc3](https://github.com/angular/angular/commit/19fcfc3))
* **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([56f44be](https://github.com/angular/angular/commit/56f44be)) * **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([56f44be](https://github.com/angular/angular/commit/56f44be))
* **core:** ignore comment nodes under unsafe elements ([#25879](https://github.com/angular/angular/issues/25879)) ([d5cbcef](https://github.com/angular/angular/commit/d5cbcef)) * **core:** ignore comment nodes under unsafe elements ([#25879](https://github.com/angular/angular/issues/25879)) ([d5cbcef](https://github.com/angular/angular/commit/d5cbcef))
* **core:** Remove static dependency from @angular/core to @angular/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([d042c4a](https://github.com/angular/angular/commit/d042c4a)) * **core:** Remove static dependency from [@angular](https://github.com/angular)/core to [@angular](https://github.com/angular)/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([d042c4a](https://github.com/angular/angular/commit/d042c4a))
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([95743e3](https://github.com/angular/angular/commit/95743e3)) * **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([95743e3](https://github.com/angular/angular/commit/95743e3))
* **bazel:** unknown replay compiler error in windows ([#26711](https://github.com/angular/angular/issues/26711)) ([aed95fd](https://github.com/angular/angular/commit/aed95fd)) * **bazel:** unknown replay compiler error in windows ([#26711](https://github.com/angular/angular/issues/26711)) ([aed95fd](https://github.com/angular/angular/commit/aed95fd))
* **core:** ensure that `ɵdefineNgModule` is available in flat-file formats ([#26403](https://github.com/angular/angular/issues/26403)) ([a64859b](https://github.com/angular/angular/commit/a64859b)) * **core:** ensure that `ɵdefineNgModule` is available in flat-file formats ([#26403](https://github.com/angular/angular/issues/26403)) ([a64859b](https://github.com/angular/angular/commit/a64859b))
@ -1350,7 +1185,7 @@ This release contains various API docs improvements.
* **compiler:** generate inputs with aliases properly ([#26774](https://github.com/angular/angular/issues/26774)) ([19fcfc3](https://github.com/angular/angular/commit/19fcfc3)) * **compiler:** generate inputs with aliases properly ([#26774](https://github.com/angular/angular/issues/26774)) ([19fcfc3](https://github.com/angular/angular/commit/19fcfc3))
* **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([56f44be](https://github.com/angular/angular/commit/56f44be)) * **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([56f44be](https://github.com/angular/angular/commit/56f44be))
* **core:** ignore comment nodes under unsafe elements ([#25879](https://github.com/angular/angular/issues/25879)) ([d5cbcef](https://github.com/angular/angular/commit/d5cbcef)) * **core:** ignore comment nodes under unsafe elements ([#25879](https://github.com/angular/angular/issues/25879)) ([d5cbcef](https://github.com/angular/angular/commit/d5cbcef))
* **core:** Remove static dependency from @angular/core to @angular/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([d042c4a](https://github.com/angular/angular/commit/d042c4a)) * **core:** Remove static dependency from [@angular](https://github.com/angular)/core to [@angular](https://github.com/angular)/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([d042c4a](https://github.com/angular/angular/commit/d042c4a))
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([95743e3](https://github.com/angular/angular/commit/95743e3)) * **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([95743e3](https://github.com/angular/angular/commit/95743e3))
@ -1362,7 +1197,7 @@ This release contains various API docs improvements.
### Bug Fixes ### Bug Fixes
* **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([c01f340](https://github.com/angular/angular/commit/c01f340)) * **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([c01f340](https://github.com/angular/angular/commit/c01f340))
* **core:** Remove static dependency from @angular/core to @angular/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([#26879](https://github.com/angular/angular/issues/26879)) ([257ac83](https://github.com/angular/angular/commit/257ac83)) * **core:** Remove static dependency from [@angular](https://github.com/angular)/core to [@angular](https://github.com/angular)/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([#26879](https://github.com/angular/angular/issues/26879)) ([257ac83](https://github.com/angular/angular/commit/257ac83))
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([b3c6409](https://github.com/angular/angular/commit/b3c6409)) * **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([b3c6409](https://github.com/angular/angular/commit/b3c6409))
@ -1439,7 +1274,7 @@ To learn about the release highlights and our new CLI-powered update workflow fo
* **compiler:** update compiler to flatten nested template fns ([#24943](https://github.com/angular/angular/issues/24943)) ([fe14f18](https://github.com/angular/angular/commit/fe14f18)) * **compiler:** update compiler to flatten nested template fns ([#24943](https://github.com/angular/angular/issues/24943)) ([fe14f18](https://github.com/angular/angular/commit/fe14f18))
* **compiler:** update compiler to generate new slot allocations ([#25607](https://github.com/angular/angular/issues/25607)) ([27e2039](https://github.com/angular/angular/commit/27e2039)) * **compiler:** update compiler to generate new slot allocations ([#25607](https://github.com/angular/angular/issues/25607)) ([27e2039](https://github.com/angular/angular/commit/27e2039))
* **core:** In Testability.whenStable update callback, pass more complete ([#25010](https://github.com/angular/angular/issues/25010)) ([16c03c0](https://github.com/angular/angular/commit/16c03c0)) * **core:** In Testability.whenStable update callback, pass more complete ([#25010](https://github.com/angular/angular/issues/25010)) ([16c03c0](https://github.com/angular/angular/commit/16c03c0))
* **core:** add missing `peerDependency ` to `@angular/compiler` ([#26033](https://github.com/angular/angular/issues/26033)) ([549de1e](https://github.com/angular/angular/commit/549de1e)), closes [/github.com/angular/angular/commit/919f42fea1df4b9e38b7d688aef5f2de668e9d3e#diff-58563046c4439699f2e6a89187099a54](https://github.com//github.com/angular/angular/commit/919f42fea1df4b9e38b7d688aef5f2de668e9d3e/issues/diff-58563046c4439699f2e6a89187099a54) * **core:** add missing `peerDependency ` to `[@angular](https://github.com/angular)/compiler` ([#26033](https://github.com/angular/angular/issues/26033)) ([549de1e](https://github.com/angular/angular/commit/549de1e)), closes [/github.com/angular/angular/commit/919f42fea1df4b9e38b7d688aef5f2de668e9d3e#diff-58563046c4439699f2e6a89187099a54](https://github.com//github.com/angular/angular/commit/919f42fea1df4b9e38b7d688aef5f2de668e9d3e/issues/diff-58563046c4439699f2e6a89187099a54)
* **core:** allow null value for renderer setElement(…) ([#17065](https://github.com/angular/angular/issues/17065)) ([ff15043](https://github.com/angular/angular/commit/ff15043)), closes [#13686](https://github.com/angular/angular/issues/13686) * **core:** allow null value for renderer setElement(…) ([#17065](https://github.com/angular/angular/issues/17065)) ([ff15043](https://github.com/angular/angular/commit/ff15043)), closes [#13686](https://github.com/angular/angular/issues/13686)
* **core:** do not clear element content when using shadow dom ([#24861](https://github.com/angular/angular/issues/24861)) ([6e828bb](https://github.com/angular/angular/commit/6e828bb)) * **core:** do not clear element content when using shadow dom ([#24861](https://github.com/angular/angular/issues/24861)) ([6e828bb](https://github.com/angular/angular/commit/6e828bb))
* **core:** size regression with closure compiler ([#25531](https://github.com/angular/angular/issues/25531)) ([1f59f2f](https://github.com/angular/angular/commit/1f59f2f)) * **core:** size regression with closure compiler ([#25531](https://github.com/angular/angular/issues/25531)) ([1f59f2f](https://github.com/angular/angular/commit/1f59f2f))
@ -1885,7 +1720,7 @@ To learn about the release highlights and our new CLI-powered update workflow fo
* **upgrade:** propagate return value of resumeBootstrap ([#22754](https://github.com/angular/angular/issues/22754)) ([a2330ff](https://github.com/angular/angular/commit/a2330ff)), closes [#22723](https://github.com/angular/angular/issues/22723) * **upgrade:** propagate return value of resumeBootstrap ([#22754](https://github.com/angular/angular/issues/22754)) ([a2330ff](https://github.com/angular/angular/commit/a2330ff)), closes [#22723](https://github.com/angular/angular/issues/22723)
* **upgrade:** two-way binding and listening for event ([#22772](https://github.com/angular/angular/issues/22772)) ([2b3de63](https://github.com/angular/angular/commit/2b3de63)), closes [#22734](https://github.com/angular/angular/issues/22734) * **upgrade:** two-way binding and listening for event ([#22772](https://github.com/angular/angular/issues/22772)) ([2b3de63](https://github.com/angular/angular/commit/2b3de63)), closes [#22734](https://github.com/angular/angular/issues/22734)
* **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([8a85888](https://github.com/angular/angular/commit/8a85888)), closes [#22392](https://github.com/angular/angular/issues/22392) * **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([8a85888](https://github.com/angular/angular/commit/8a85888)), closes [#22392](https://github.com/angular/angular/issues/22392)
* **upgrade:** correctly handle `=` bindings in `@angular/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([f089bf5](https://github.com/angular/angular/commit/f089bf5)) * **upgrade:** correctly handle `=` bindings in `[@angular](https://github.com/angular)/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([f089bf5](https://github.com/angular/angular/commit/f089bf5))
* **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([13ab91e](https://github.com/angular/angular/commit/13ab91e)), closes [#22175](https://github.com/angular/angular/issues/22175) * **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([13ab91e](https://github.com/angular/angular/commit/13ab91e)), closes [#22175](https://github.com/angular/angular/issues/22175)
@ -2020,7 +1855,7 @@ To learn about the release highlights and our new CLI-powered update workflow fo
* **router:** don't mutate route configs ([#22358](https://github.com/angular/angular/issues/22358)) ([8f0a064](https://github.com/angular/angular/commit/8f0a064)), closes [#22203](https://github.com/angular/angular/issues/22203) * **router:** don't mutate route configs ([#22358](https://github.com/angular/angular/issues/22358)) ([8f0a064](https://github.com/angular/angular/commit/8f0a064)), closes [#22203](https://github.com/angular/angular/issues/22203)
* **router:** fix URL serialization so special characters are only encoded where needed ([#22337](https://github.com/angular/angular/issues/22337)) ([789a47e](https://github.com/angular/angular/commit/789a47e)), closes [#10280](https://github.com/angular/angular/issues/10280) * **router:** fix URL serialization so special characters are only encoded where needed ([#22337](https://github.com/angular/angular/issues/22337)) ([789a47e](https://github.com/angular/angular/commit/789a47e)), closes [#10280](https://github.com/angular/angular/issues/10280)
* **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([4aef9de](https://github.com/angular/angular/commit/4aef9de)), closes [#22392](https://github.com/angular/angular/issues/22392) * **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([4aef9de](https://github.com/angular/angular/commit/4aef9de)), closes [#22392](https://github.com/angular/angular/issues/22392)
* **upgrade:** correctly handle `=` bindings in `@angular/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([6638390](https://github.com/angular/angular/commit/6638390)) * **upgrade:** correctly handle `=` bindings in `[@angular](https://github.com/angular)/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([6638390](https://github.com/angular/angular/commit/6638390))
* **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([a9a0e27](https://github.com/angular/angular/commit/a9a0e27)), closes [#22175](https://github.com/angular/angular/issues/22175) * **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([a9a0e27](https://github.com/angular/angular/commit/a9a0e27)), closes [#22175](https://github.com/angular/angular/issues/22175)
@ -2034,7 +1869,7 @@ To learn about the release highlights and our new CLI-powered update workflow fo
* **platform-server:** generate correct stylings for camel case names ([#22263](https://github.com/angular/angular/issues/22263)) ([de02a7a](https://github.com/angular/angular/commit/de02a7a)), closes [#19235](https://github.com/angular/angular/issues/19235) * **platform-server:** generate correct stylings for camel case names ([#22263](https://github.com/angular/angular/issues/22263)) ([de02a7a](https://github.com/angular/angular/commit/de02a7a)), closes [#19235](https://github.com/angular/angular/issues/19235)
* **router:** don't mutate route configs ([#22358](https://github.com/angular/angular/issues/22358)) ([8f0a064](https://github.com/angular/angular/commit/8f0a064)), closes [#22203](https://github.com/angular/angular/issues/22203) * **router:** don't mutate route configs ([#22358](https://github.com/angular/angular/issues/22358)) ([8f0a064](https://github.com/angular/angular/commit/8f0a064)), closes [#22203](https://github.com/angular/angular/issues/22203)
* **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([4aef9de](https://github.com/angular/angular/commit/4aef9de)), closes [#22392](https://github.com/angular/angular/issues/22392) * **upgrade:** correctly destroy nested downgraded component ([#22400](https://github.com/angular/angular/issues/22400)) ([4aef9de](https://github.com/angular/angular/commit/4aef9de)), closes [#22392](https://github.com/angular/angular/issues/22392)
* **upgrade:** correctly handle `=` bindings in `@angular/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([6638390](https://github.com/angular/angular/commit/6638390)) * **upgrade:** correctly handle `=` bindings in `[@angular](https://github.com/angular)/upgrade` ([#22167](https://github.com/angular/angular/issues/22167)) ([6638390](https://github.com/angular/angular/commit/6638390))
* **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([a9a0e27](https://github.com/angular/angular/commit/a9a0e27)), closes [#22175](https://github.com/angular/angular/issues/22175) * **upgrade:** fix empty transclusion content with AngularJS@>=1.5.8 ([#22167](https://github.com/angular/angular/issues/22167)) ([a9a0e27](https://github.com/angular/angular/commit/a9a0e27)), closes [#22175](https://github.com/angular/angular/issues/22175)
@ -2481,7 +2316,7 @@ Note: Due to an animation fix back in 5.1.1 ([c2b3792](https://github.com/angula
* **platform-server:** provide a way to hook into renderModule* ([#19023](https://github.com/angular/angular/issues/19023)) ([8dfc3c3](https://github.com/angular/angular/commit/8dfc3c3)) * **platform-server:** provide a way to hook into renderModule* ([#19023](https://github.com/angular/angular/issues/19023)) ([8dfc3c3](https://github.com/angular/angular/commit/8dfc3c3))
* **router:** add ActivationStart/End events ([8f79150](https://github.com/angular/angular/commit/8f79150)) * **router:** add ActivationStart/End events ([8f79150](https://github.com/angular/angular/commit/8f79150))
* **router:** add events tracking activation of individual routes ([49cd851](https://github.com/angular/angular/commit/49cd851)) * **router:** add events tracking activation of individual routes ([49cd851](https://github.com/angular/angular/commit/49cd851))
* **service-worker:** introduce the @angular/service-worker package ([#19274](https://github.com/angular/angular/issues/19274)) ([d442b68](https://github.com/angular/angular/commit/d442b68)) * **service-worker:** introduce the [@angular](https://github.com/angular)/service-worker package ([#19274](https://github.com/angular/angular/issues/19274)) ([d442b68](https://github.com/angular/angular/commit/d442b68))
* **upgrade:** propagate touched state of NgModelController ([59c23c7](https://github.com/angular/angular/commit/59c23c7)) * **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)) * **upgrade:** support lazy-loading Angular module into AngularJS app ([30e76fc](https://github.com/angular/angular/commit/30e76fc))
* update angular to support TypeScript 2.4 ([ca5aeba](https://github.com/angular/angular/commit/ca5aeba)) * update angular to support TypeScript 2.4 ([ca5aeba](https://github.com/angular/angular/commit/ca5aeba))
@ -2705,7 +2540,7 @@ Because of multiple bugs and browser inconsistencies, we have dropped the intl a
### Bug Fixes ### Bug Fixes
* **animations:** do not leak DOM nodes/styling for host triggered animations ([#18853](https://github.com/angular/angular/issues/18853)) ([1cc3fe2](https://github.com/angular/angular/commit/1cc3fe2)), closes [#18606](https://github.com/angular/angular/issues/18606) * **animations:** do not leak DOM nodes/styling for host triggered animations ([#18853](https://github.com/angular/angular/issues/18853)) ([1cc3fe2](https://github.com/angular/angular/commit/1cc3fe2)), closes [#18606](https://github.com/angular/angular/issues/18606)
* **common:** fix improper packaging for @angular/common/http ([#18613](https://github.com/angular/angular/issues/18613)) ([a203a95](https://github.com/angular/angular/commit/a203a95)) * **common:** fix improper packaging for [@angular](https://github.com/angular)/common/http ([#18613](https://github.com/angular/angular/issues/18613)) ([a203a95](https://github.com/angular/angular/commit/a203a95))
* **common:** fix XSSI prefix stripping by using JSON.parse always ([#18466](https://github.com/angular/angular/issues/18466)) ([8821723](https://github.com/angular/angular/commit/8821723)), closes [#18396](https://github.com/angular/angular/issues/18396) [#18453](https://github.com/angular/angular/issues/18453) * **common:** fix XSSI prefix stripping by using JSON.parse always ([#18466](https://github.com/angular/angular/issues/18466)) ([8821723](https://github.com/angular/angular/commit/8821723)), closes [#18396](https://github.com/angular/angular/issues/18396) [#18453](https://github.com/angular/angular/issues/18453)
* **compiler:** normalize the locale name ([#18963](https://github.com/angular/angular/issues/18963)) ([497e017](https://github.com/angular/angular/commit/497e017)) * **compiler:** normalize the locale name ([#18963](https://github.com/angular/angular/issues/18963)) ([497e017](https://github.com/angular/angular/commit/497e017))
* **core:** complete EventEmitter in QueryList on component destroy ([#18902](https://github.com/angular/angular/issues/18902)) ([7d137d7](https://github.com/angular/angular/commit/7d137d7)), closes [#18741](https://github.com/angular/angular/issues/18741) * **core:** complete EventEmitter in QueryList on component destroy ([#18902](https://github.com/angular/angular/issues/18902)) ([7d137d7](https://github.com/angular/angular/commit/7d137d7)), closes [#18741](https://github.com/angular/angular/issues/18741)
@ -3046,7 +2881,7 @@ Note: the 4.4.0 release on npm accidentally glitched-out midway, so we cut 4.4.1
* **compiler-cli:** allow '==' to compare nullable types ([#16731](https://github.com/angular/angular/issues/16731)) ([d761059](https://github.com/angular/angular/commit/d761059)) * **compiler-cli:** allow '==' to compare nullable types ([#16731](https://github.com/angular/angular/issues/16731)) ([d761059](https://github.com/angular/angular/commit/d761059))
* **core:** detach projected views when a parent view is destroyed ([#16592](https://github.com/angular/angular/issues/16592)) ([f0f6544](https://github.com/angular/angular/commit/f0f6544)), closes [#15578](https://github.com/angular/angular/issues/15578) * **core:** detach projected views when a parent view is destroyed ([#16592](https://github.com/angular/angular/issues/16592)) ([f0f6544](https://github.com/angular/angular/commit/f0f6544)), closes [#15578](https://github.com/angular/angular/issues/15578)
* **core:** projected views should be dirty checked when the declaring component is dirty checked. ([#16592](https://github.com/angular/angular/issues/16592)) ([fcc91d8](https://github.com/angular/angular/commit/fcc91d8)), closes [#14321](https://github.com/angular/angular/issues/14321) * **core:** projected views should be dirty checked when the declaring component is dirty checked. ([#16592](https://github.com/angular/angular/issues/16592)) ([fcc91d8](https://github.com/angular/angular/commit/fcc91d8)), closes [#14321](https://github.com/angular/angular/issues/14321)
* **http:** flatten metadata for @angular/http/testing ([9da6340](https://github.com/angular/angular/commit/9da6340)), closes [#15521](https://github.com/angular/angular/issues/15521) * **http:** flatten metadata for [@angular](https://github.com/angular)/http/testing ([9da6340](https://github.com/angular/angular/commit/9da6340)), closes [#15521](https://github.com/angular/angular/issues/15521)
* **http:** honor RequestArgs.search and RequestArgs.params map type ([aef5245](https://github.com/angular/angular/commit/aef5245)), closes [#15761](https://github.com/angular/angular/issues/15761) [#16392](https://github.com/angular/angular/issues/16392) * **http:** honor RequestArgs.search and RequestArgs.params map type ([aef5245](https://github.com/angular/angular/commit/aef5245)), closes [#15761](https://github.com/angular/angular/issues/15761) [#16392](https://github.com/angular/angular/issues/16392)
* **http:** introduce encodingHint for text() for better ArrayBuffer support ([7ae7a84](https://github.com/angular/angular/commit/7ae7a84)), closes [#15932](https://github.com/angular/angular/issues/15932) [#16420](https://github.com/angular/angular/issues/16420) * **http:** introduce encodingHint for text() for better ArrayBuffer support ([7ae7a84](https://github.com/angular/angular/commit/7ae7a84)), closes [#15932](https://github.com/angular/angular/issues/15932) [#16420](https://github.com/angular/angular/issues/16420)
* **router:** fix redirect to a URL with a param having multiple values ([#16376](https://github.com/angular/angular/issues/16376)) ([5d4b36f](https://github.com/angular/angular/commit/5d4b36f)), closes [#16310](https://github.com/angular/angular/issues/16310) * **router:** fix redirect to a URL with a param having multiple values ([#16376](https://github.com/angular/angular/issues/16376)) ([5d4b36f](https://github.com/angular/angular/commit/5d4b36f)), closes [#16310](https://github.com/angular/angular/issues/16310)
@ -3102,7 +2937,7 @@ Note: the 4.4.0 release on npm accidentally glitched-out midway, so we cut 4.4.1
* **compiler:** avoid a `...null` spread in extraction ([#16547](https://github.com/angular/angular/issues/16547)) ([d0e1688](https://github.com/angular/angular/commit/d0e1688)) * **compiler:** avoid a `...null` spread in extraction ([#16547](https://github.com/angular/angular/issues/16547)) ([d0e1688](https://github.com/angular/angular/commit/d0e1688))
* **core:** detach projected views when a parent view is destroyed ([#16592](https://github.com/angular/angular/issues/16592)) ([ee6705a](https://github.com/angular/angular/commit/ee6705a)), closes [#15578](https://github.com/angular/angular/issues/15578) * **core:** detach projected views when a parent view is destroyed ([#16592](https://github.com/angular/angular/issues/16592)) ([ee6705a](https://github.com/angular/angular/commit/ee6705a)), closes [#15578](https://github.com/angular/angular/issues/15578)
* **core:** projected views should be dirty checked when the declaring component is dirty checked. ([#16592](https://github.com/angular/angular/issues/16592)) ([9218812](https://github.com/angular/angular/commit/9218812)), closes [#14321](https://github.com/angular/angular/issues/14321) * **core:** projected views should be dirty checked when the declaring component is dirty checked. ([#16592](https://github.com/angular/angular/issues/16592)) ([9218812](https://github.com/angular/angular/commit/9218812)), closes [#14321](https://github.com/angular/angular/issues/14321)
* **http:** flatten metadata for @angular/http/testing ([9c70a3c](https://github.com/angular/angular/commit/9c70a3c)), closes [#15521](https://github.com/angular/angular/issues/15521) * **http:** flatten metadata for [@angular](https://github.com/angular)/http/testing ([9c70a3c](https://github.com/angular/angular/commit/9c70a3c)), closes [#15521](https://github.com/angular/angular/issues/15521)
* **http:** honor RequestArgs.search and RequestArgs.params map type ([63066f7](https://github.com/angular/angular/commit/63066f7)), closes [#15761](https://github.com/angular/angular/issues/15761) [#16392](https://github.com/angular/angular/issues/16392) * **http:** honor RequestArgs.search and RequestArgs.params map type ([63066f7](https://github.com/angular/angular/commit/63066f7)), closes [#15761](https://github.com/angular/angular/issues/15761) [#16392](https://github.com/angular/angular/issues/16392)
* **http:** introduce encodingHint for text() for better ArrayBuffer support ([ec3b6e9](https://github.com/angular/angular/commit/ec3b6e9)), closes [#15932](https://github.com/angular/angular/issues/15932) [#16420](https://github.com/angular/angular/issues/16420) * **http:** introduce encodingHint for text() for better ArrayBuffer support ([ec3b6e9](https://github.com/angular/angular/commit/ec3b6e9)), closes [#15932](https://github.com/angular/angular/issues/15932) [#16420](https://github.com/angular/angular/issues/16420)
* **router:** fix redirect to a URL with a param having multiple values ([#16376](https://github.com/angular/angular/issues/16376)) ([915eae5](https://github.com/angular/angular/commit/915eae5)), closes [#16310](https://github.com/angular/angular/issues/16310) * **router:** fix redirect to a URL with a param having multiple values ([#16376](https://github.com/angular/angular/issues/16376)) ([915eae5](https://github.com/angular/angular/commit/915eae5)), closes [#16310](https://github.com/angular/angular/issues/16310)
@ -3732,7 +3567,7 @@ Note: the 4.0.0-rc.0 release on npm accidentally omitted one bug fix, so we cut
* **core:** add isStable Observable property to ApplicationRef to indicate when it's stable and unstable ([#14337](https://github.com/angular/angular/issues/14337)) ([c481798](https://github.com/angular/angular/commit/c481798)) * **core:** add isStable Observable property to ApplicationRef to indicate when it's stable and unstable ([#14337](https://github.com/angular/angular/issues/14337)) ([c481798](https://github.com/angular/angular/commit/c481798))
* **platform-server:** add API to render Module and ModuleFactory to string ([#14381](https://github.com/angular/angular/issues/14381)) ([b4d444a](https://github.com/angular/angular/commit/b4d444a)) * **platform-server:** add API to render Module and ModuleFactory to string ([#14381](https://github.com/angular/angular/issues/14381)) ([b4d444a](https://github.com/angular/angular/commit/b4d444a))
* **platform-server:** Implement PlatformLocation for platformServer() ([#14405](https://github.com/angular/angular/issues/14405)) ([9e28568](https://github.com/angular/angular/commit/9e28568)) * **platform-server:** Implement PlatformLocation for platformServer() ([#14405](https://github.com/angular/angular/issues/14405)) ([9e28568](https://github.com/angular/angular/commit/9e28568))
* **platform-server:** support @angular/http from @angular/platform-server ([9559d3e](https://github.com/angular/angular/commit/9559d3e)) * **platform-server:** support [@angular](https://github.com/angular)/http from [@angular](https://github.com/angular)/platform-server ([9559d3e](https://github.com/angular/angular/commit/9559d3e))
* **tsc-wrapped:** add an option to `ngc` to bundle metadata ([#14509](https://github.com/angular/angular/issues/14509)) ([3b89670](https://github.com/angular/angular/commit/3b89670)) * **tsc-wrapped:** add an option to `ngc` to bundle metadata ([#14509](https://github.com/angular/angular/issues/14509)) ([3b89670](https://github.com/angular/angular/commit/3b89670))
@ -4693,7 +4528,7 @@ Note: The 2.2.0-beta.0 release also contains all the changes present in the 2.1.
* **compiler:** properly shim `:host:before` and `:host(:before)` ([#12171](https://github.com/angular/angular/issues/12171)) ([aa92512](https://github.com/angular/angular/commit/aa92512)), closes [#12165](https://github.com/angular/angular/issues/12165) * **compiler:** properly shim `:host:before` and `:host(:before)` ([#12171](https://github.com/angular/angular/issues/12171)) ([aa92512](https://github.com/angular/angular/commit/aa92512)), closes [#12165](https://github.com/angular/angular/issues/12165)
* **compiler:** validate `@HostBinding` name ([#12139](https://github.com/angular/angular/issues/12139)) ([13ecc14](https://github.com/angular/angular/commit/13ecc14)) * **compiler:** validate `@HostBinding` name ([#12139](https://github.com/angular/angular/issues/12139)) ([13ecc14](https://github.com/angular/angular/commit/13ecc14))
* **compiler-cli:** don't clone static symbols when simplifying annotation metadata ([#12158](https://github.com/angular/angular/issues/12158)) ([8c477b2](https://github.com/angular/angular/commit/8c477b2)) * **compiler-cli:** don't clone static symbols when simplifying annotation metadata ([#12158](https://github.com/angular/angular/issues/12158)) ([8c477b2](https://github.com/angular/angular/commit/8c477b2))
* **compiler-cli:** remove peerDependency on @angular/platform-server ([#12122](https://github.com/angular/angular/issues/12122)) ([71b7654](https://github.com/angular/angular/commit/71b7654)) * **compiler-cli:** remove peerDependency on [@angular](https://github.com/angular)/platform-server ([#12122](https://github.com/angular/angular/issues/12122)) ([71b7654](https://github.com/angular/angular/commit/71b7654))
* **compiler-cli:** remove unused parse5 dependency from package.json ([eaaec69](https://github.com/angular/angular/commit/eaaec69)) * **compiler-cli:** remove unused parse5 dependency from package.json ([eaaec69](https://github.com/angular/angular/commit/eaaec69))
* **forms:** allow optional fields with pattern and minlength validators ([#12147](https://github.com/angular/angular/issues/12147)) ([d22eeb7](https://github.com/angular/angular/commit/d22eeb7)) * **forms:** allow optional fields with pattern and minlength validators ([#12147](https://github.com/angular/angular/issues/12147)) ([d22eeb7](https://github.com/angular/angular/commit/d22eeb7))
* **forms:** properly validate blank strings with minlength ([#12091](https://github.com/angular/angular/issues/12091)) ([f50c1da](https://github.com/angular/angular/commit/f50c1da)) * **forms:** properly validate blank strings with minlength ([#12091](https://github.com/angular/angular/issues/12091)) ([f50c1da](https://github.com/angular/angular/commit/f50c1da))

View File

@ -222,7 +222,6 @@ The following is the list of supported scopes:
* **router** * **router**
* **service-worker** * **service-worker**
* **upgrade** * **upgrade**
* **zone.js**
There are currently a few exceptions to the "use package name" rule: There are currently a few exceptions to the "use package name" rule:

View File

@ -18,11 +18,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# Fetch rules_nodejs so we can install our npm dependencies # Fetch rules_nodejs so we can install our npm dependencies
http_archive( http_archive(
name = "build_bazel_rules_nodejs", name = "build_bazel_rules_nodejs",
patch_args = ["-p1"], sha256 = "e04a82a72146bfbca2d0575947daa60fda1878c8d3a3afe868a8ec39a6b968bb",
# Patch https://github.com/bazelbuild/rules_nodejs/pull/903 urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.31.1/rules_nodejs-0.31.1.tar.gz"],
patches = ["//tools:rollup_bundle_commonjs_ignoreGlobal.patch"],
sha256 = "6d4edbf28ff6720aedf5f97f9b9a7679401bf7fca9d14a0fff80f644a99992b4",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.32.2/rules_nodejs-0.32.2.tar.gz"],
) )
# Check the bazel version and download npm dependencies # Check the bazel version and download npm dependencies
@ -30,7 +27,6 @@ load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "check_rules
# Bazel version must be at least the following version because: # Bazel version must be at least the following version because:
# - 0.26.0 managed_directories feature added which is required for nodejs rules 0.30.0 # - 0.26.0 managed_directories feature added which is required for nodejs rules 0.30.0
# - 0.27.0 has a fix for managed_directories after `rm -rf node_modules`
check_bazel_version( check_bazel_version(
message = """ message = """
You no longer need to install Bazel on your machine. You no longer need to install Bazel on your machine.
@ -39,7 +35,7 @@ Try running `yarn bazel` instead.
(If you did run that, check that you've got a fresh `yarn install`) (If you did run that, check that you've got a fresh `yarn install`)
""", """,
minimum_bazel_version = "0.27.0", minimum_bazel_version = "0.26.0",
) )
# The NodeJS rules version must be at least the following version because: # The NodeJS rules version must be at least the following version because:
@ -50,10 +46,7 @@ Try running `yarn bazel` instead.
# - 0.27.12 Adds NodeModuleSources provider for transtive npm deps support # - 0.27.12 Adds NodeModuleSources provider for transtive npm deps support
# - 0.30.0 yarn_install now uses symlinked node_modules with new managed directories Bazel 0.26.0 feature # - 0.30.0 yarn_install now uses symlinked node_modules with new managed directories Bazel 0.26.0 feature
# - 0.31.1 entry_point attribute of nodejs_binary & rollup_bundle is now a label # - 0.31.1 entry_point attribute of nodejs_binary & rollup_bundle is now a label
# - 0.32.0 yarn_install and npm_install no longer puts build files under symlinked node_modules check_rules_nodejs_version(minimum_version_string = "0.31.1")
# - 0.32.1 remove override of @bazel/tsetse & exclude typescript lib declarations in node_module_library transitive_declarations
# - 0.32.2 resolves bug in @bazel/hide-bazel-files postinstall step
check_rules_nodejs_version(minimum_version_string = "0.32.2")
# Setup the Node.js toolchain # Setup the Node.js toolchain
node_repositories( node_repositories(
@ -77,7 +70,19 @@ node_repositories(
yarn_install( yarn_install(
name = "npm", name = "npm",
data = [
"//:tools/npm/@angular_bazel/index.js",
"//:tools/npm/@angular_bazel/package.json",
"//:tools/postinstall-patches.js",
"//:tools/yarn/check-yarn.js",
],
package_json = "//:package.json", package_json = "//:package.json",
# Don't install devDependencies, they are large and not used under Bazel
prod_only = True,
# Temporarily disable node_modules symlinking until the fix for
# https://github.com/bazelbuild/bazel/issues/8487 makes it into a
# future Bazel release
symlink_node_modules = False,
yarn_lock = "//:yarn.lock", yarn_lock = "//:yarn.lock",
) )

View File

@ -36,14 +36,6 @@ ng serve
In your browser, open http://localhost:4200/ to see the new app run. In your browser, open http://localhost:4200/ to see the new app run.
When you use the [ng serve](cli/serve) command to build an app and serve it locally, the server automatically rebuilds the app and reloads the page when you change any of the source files. When you use the [ng serve](cli/serve) command to build an app and serve it locally, the server automatically rebuilds the app and reloads the page when you change any of the source files.
<div class="alert is-helpful">
When you run `ng new my-first-project` a new folder, named `my-first-project`, will be created in the current working directory. Since you want to be able to create files inside that folder, make sure you have sufficient rights in the current working directory before running the command.
If the current working directory is not the right place for your project, you can change to a more appropriate directory by running `cd <path-to-other-directory>` first.
</div>
## Workspaces and project files ## Workspaces and project files
The [ng new](cli/new) command creates an *Angular workspace* folder and generates a new app skeleton. The [ng new](cli/new) command creates an *Angular workspace* folder and generates a new app skeleton.

View File

@ -25,8 +25,8 @@ describe('Attribute directives', () => {
greenRb.click(); greenRb.click();
browser.actions().mouseMove(highlightedEle).perform(); browser.actions().mouseMove(highlightedEle).perform();
// Wait for up to 4s for the background color to be updated, // Wait for up to 2s for the background color to be updated,
// to account for slow environments (e.g. CI). // to account for slow environments (e.g. CI).
browser.wait(() => highlightedEle.getCssValue('background-color').then(c => c === lightGreen), 4000); browser.wait(() => highlightedEle.getCssValue('background-color').then(c => c === lightGreen), 2000);
}); });
}); });

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -18,7 +18,7 @@ export class AppComponent {
} }
deleteItem(item: Item) { deleteItem(item: Item) {
alert(`Delete the ${item.name}.`); alert(`Delete the ${item}.`);
} }
onClickMe(event?: KeyboardEvent) { onClickMe(event?: KeyboardEvent) {

View File

@ -16,17 +16,13 @@
<!-- #enddocregion checkout-form-1 --> <!-- #enddocregion checkout-form-1 -->
<div> <div>
<label for="name"> <label>Name</label>
Name <input type="text" formControlName="name">
</label>
<input id="name" type="text" formControlName="name">
</div> </div>
<div> <div>
<label for="address"> <label>Address</label>
Address <input type="text" formControlName="address">
</label>
<input id="address" type="text" formControlName="address">
</div> </div>
<button class="button" type="submit">Purchase</button> <button class="button" type="submit">Purchase</button>

View File

@ -10,6 +10,7 @@ export class AppComponent {
gender = 'female'; gender = 'female';
fly = true; fly = true;
logo = 'https://angular.io/assets/images/logos/angular/angular.png'; logo = 'https://angular.io/assets/images/logos/angular/angular.png';
heroes: string[] = ['Magneta', 'Celeritas', 'Dynama'];
inc(i: number) { inc(i: number) {
this.minutes = Math.min(5, Math.max(0, this.minutes + i)); this.minutes = Math.min(5, Math.max(0, this.minutes + i));
} }

View File

@ -1,14 +0,0 @@
// imports
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
// @NgModule decorator with its metadata
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}

View File

@ -2,49 +2,42 @@
import { browser, element, by } from 'protractor'; import { browser, element, by } from 'protractor';
// TODO Not yet complete // Not yet complete
describe('Template Syntax', () => { describe('Template Syntax', function () {
beforeAll(() => { beforeAll(function () {
browser.get(''); browser.get('');
}); });
it('should be able to use interpolation with a hero', () => { it('should be able to use interpolation with a hero', function () {
const heroInterEle = element.all(by.css('h2+p')).get(0); let heroInterEle = element.all(by.css('h2+p')).get(0);
expect(heroInterEle.getText()).toEqual('My current hero is Hercules'); expect(heroInterEle.getText()).toEqual('My current hero is Hercules');
}); });
it('should be able to use interpolation with a calculation', () => { it('should be able to use interpolation with a calculation', function () {
const theSumEles = element.all(by.cssContainingText('h3~p', 'The sum of')); let theSumEles = element.all(by.cssContainingText('h3~p', 'The sum of'));
expect(theSumEles.count()).toBe(2); expect(theSumEles.count()).toBe(2);
expect(theSumEles.get(0).getText()).toEqual('The sum of 1 + 1 is 2'); expect(theSumEles.get(0).getText()).toEqual('The sum of 1 + 1 is 2');
expect(theSumEles.get(1).getText()).toEqual('The sum of 1 + 1 is not 4'); expect(theSumEles.get(1).getText()).toEqual('The sum of 1 + 1 is not 4');
}); });
it('should be able to use class binding syntax', () => { it('should be able to use class binding syntax', function () {
const specialEle = element(by.cssContainingText('div', 'Special')); let specialEle = element(by.cssContainingText('div', 'Special'));
expect(specialEle.getAttribute('class')).toMatch('special'); expect(specialEle.getAttribute('class')).toMatch('special');
}); });
it('should be able to use style binding syntax', () => { it('should be able to use style binding syntax', function () {
const specialButtonEle = element(by.cssContainingText('div.special~button', 'button')); let specialButtonEle = element(by.cssContainingText('div.special~button', 'button'));
expect(specialButtonEle.getAttribute('style')).toMatch('color: red'); expect(specialButtonEle.getAttribute('style')).toMatch('color: red');
}); });
it('should two-way bind to sizer', async () => { it('should two-way bind to sizer', async () => {
const div = element(by.css('div#two-way-1')); let div = element(by.css('div#two-way-1'));
const incButton = div.element(by.buttonText('+')); let incButton = div.element(by.buttonText('+'));
const input = div.element(by.css('input')); let input = div.element(by.css('input'));
const initSize = await input.getAttribute('value'); let initSize = await input.getAttribute('value');
incButton.click(); incButton.click();
expect(input.getAttribute('value')).toEqual((+initSize + 1).toString()); expect(input.getAttribute('value')).toEqual((+initSize + 1).toString());
}); });
});
it('should change SVG rectangle\'s fill color on click', async () => {
const div = element(by.css('app-svg'));
const colorSquare = div.element(by.css('rect'));
const initialColor = await colorSquare.getAttribute('fill');
colorSquare.click();
expect(colorSquare.getAttribute('fill')).not.toEqual(initialColor);
});
});

View File

@ -38,7 +38,6 @@
<a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br> <a href="#safe-navigation-operator">Safe navigation operator <i>?.</i></a><br>
<a href="#non-null-assertion-operator">Non-null assertion operator <i>!.</i></a><br> <a href="#non-null-assertion-operator">Non-null assertion operator <i>!.</i></a><br>
<a href="#enums">Enums</a><br> <a href="#enums">Enums</a><br>
<a href="#svg-templates">SVG Templates</a><br>
<!-- Interpolation and expressions --> <!-- Interpolation and expressions -->
<hr><h2 id="interpolation">Interpolation</h2> <hr><h2 id="interpolation">Interpolation</h2>
@ -443,7 +442,7 @@ button</button>
<!-- #docregion without-NgModel --> <!-- #docregion without-NgModel -->
<input [value]="currentHero.name" <input [value]="currentHero.name"
(input)="updateCurrentHeroName($event)"> (input)="currentHero.name=$event.target.value" >
<!-- #enddocregion without-NgModel --> <!-- #enddocregion without-NgModel -->
without NgModel without NgModel
<br> <br>
@ -753,7 +752,7 @@ bindon-ngModel
<div> <div>
<!-- pipe price to USD and display the $ symbol --> <!-- pipe price to USD and display the $ symbol -->
<label>Price: </label>{{product.price | currency:'USD':'symbol'}} <label>Price: </label>{{product.price | currency:'USD':true}}
</div> </div>
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
@ -858,9 +857,3 @@ The null hero's name is {{nullHero && nullHero.name}}
</p> </p>
<a class="to-toc" href="#toc">top</a> <a class="to-toc" href="#toc">top</a>
<hr><h2 id="svg-templates">SVG Templates</h2>
<!-- #docregion svg-templates -->
<app-svg></app-svg>
<!-- #enddocregion svg-templates -->
<a class="to-toc" href="#toc">top</a>

View File

@ -5,7 +5,7 @@ import { AfterViewInit, Component, ElementRef, OnInit, QueryList, ViewChildren }
import { Hero } from './hero'; import { Hero } from './hero';
export enum Color {Red, Green, Blue} export enum Color {Red, Green, Blue};
/** /**
* Giant grab bag of stuff to drive the chapter * Giant grab bag of stuff to drive the chapter
@ -66,10 +66,6 @@ export class AppComponent implements AfterViewInit, OnInit {
currentHero: Hero; currentHero: Hero;
updateCurrentHeroName(event: Event) {
this.currentHero.name = (event.target as any).value;
}
deleteHero(hero?: Hero) { deleteHero(hero?: Hero) {
this.alert(`Delete ${hero ? hero.name : 'the hero'}.`); this.alert(`Delete ${hero ? hero.name : 'the hero'}.`);
} }
@ -109,13 +105,13 @@ export class AppComponent implements AfterViewInit, OnInit {
get nullHero(): Hero { return null; } get nullHero(): Hero { return null; }
onClickMe(event?: MouseEvent) { onClickMe(event?: KeyboardEvent) {
const evtMsg = event ? ' Event target class is ' + (event.target as HTMLElement).className : ''; let evtMsg = event ? ' Event target class is ' + (<HTMLElement>event.target).className : '';
this.alert('Click me.' + evtMsg); this.alert('Click me.' + evtMsg);
} }
onSave(event?: MouseEvent) { onSave(event?: KeyboardEvent) {
const evtMsg = event ? ' Event target is ' + (event.target as HTMLElement).textContent : ''; let evtMsg = event ? ' Event target is ' + (<HTMLElement>event.target).textContent : '';
this.alert('Saved.' + evtMsg); this.alert('Saved.' + evtMsg);
if (event) { event.stopPropagation(); } if (event) { event.stopPropagation(); }
} }
@ -144,9 +140,9 @@ export class AppComponent implements AfterViewInit, OnInit {
setCurrentClasses() { setCurrentClasses() {
// CSS classes: added/removed per current state of component properties // CSS classes: added/removed per current state of component properties
this.currentClasses = { this.currentClasses = {
saveable: this.canSave, 'saveable': this.canSave,
modified: !this.isUnchanged, 'modified': !this.isUnchanged,
special: this.isSpecial 'special': this.isSpecial
}; };
} }
// #enddocregion setClasses // #enddocregion setClasses
@ -168,7 +164,7 @@ export class AppComponent implements AfterViewInit, OnInit {
// #enddocregion trackByHeroes // #enddocregion trackByHeroes
// #docregion trackById // #docregion trackById
trackById(index: number, item: any): number { return item.id; } trackById(index: number, item: any): number { return item['id']; }
// #enddocregion trackById // #enddocregion trackById
} }

View File

@ -8,7 +8,6 @@ import { ClickDirective, ClickDirective2 } from './click.directive';
import { HeroFormComponent } from './hero-form.component'; import { HeroFormComponent } from './hero-form.component';
import { heroSwitchComponents } from './hero-switch.components'; import { heroSwitchComponents } from './hero-switch.components';
import { SizerComponent } from './sizer.component'; import { SizerComponent } from './sizer.component';
import { SvgComponent } from './svg.component';
@NgModule({ @NgModule({
imports: [ imports: [
@ -23,8 +22,7 @@ import { SvgComponent } from './svg.component';
heroSwitchComponents, heroSwitchComponents,
ClickDirective, ClickDirective,
ClickDirective2, ClickDirective2,
SizerComponent, SizerComponent
SvgComponent
], ],
bootstrap: [ AppComponent ] bootstrap: [ AppComponent ]
}) })

View File

@ -1,4 +1,4 @@
/* tslint:disable directive-selector directive-class-suffix */ /* tslint:disable use-output-property-decorator directive-class-suffix */
// #docplaster // #docplaster
import { Directive, ElementRef, EventEmitter, Output } from '@angular/core'; import { Directive, ElementRef, EventEmitter, Output } from '@angular/core';

View File

@ -15,11 +15,10 @@ export class HeroFormComponent {
@Input() hero: Hero; @Input() hero: Hero;
@ViewChild('heroForm', {static: false}) form: NgForm; @ViewChild('heroForm', {static: false}) form: NgForm;
// tslint:disable-next-line:variable-name
private _submitMessage = ''; private _submitMessage = '';
get submitMessage() { get submitMessage() {
if (this.form && !this.form.valid) { if (!this.form.valid) {
this._submitMessage = ''; this._submitMessage = '';
} }
return this._submitMessage; return this._submitMessage;

View File

@ -1,4 +0,0 @@
svg {
display: block;
width: 100%;
}

View File

@ -1,6 +0,0 @@
<svg>
<g>
<rect x="0" y="0" width="100" height="100" [attr.fill]="fillColor" (click)="changeColor()" />
<text x="120" y="50">click the rectangle to change the fill color</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 201 B

View File

@ -1,17 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-svg',
templateUrl: './svg.component.svg',
styleUrls: ['./svg.component.css']
})
export class SvgComponent {
fillColor = 'rgb(255, 0, 0)';
changeColor() {
const r = Math.floor(Math.random() * 256);
const g = Math.floor(Math.random() * 256);
const b = Math.floor(Math.random() * 256);
this.fillColor = `rgb(${r}, ${g}, ${b})`;
}
}

View File

@ -1,4 +1,8 @@
/* HeroesComponent's private CSS styles */ /* HeroesComponent's private CSS styles */
.selected {
background-color: #CFD8DC !important;
color: white;
}
.heroes { .heroes {
margin: 0 0 2em 0; margin: 0 0 2em 0;
list-style-type: none; list-style-type: none;
@ -15,18 +19,18 @@
height: 1.6em; height: 1.6em;
border-radius: 4px; border-radius: 4px;
} }
.heroes li.selected:hover {
background-color: #BBD8DC !important;
color: white;
}
.heroes li:hover { .heroes li:hover {
color: #607D8B; color: #607D8B;
background-color: #DDD; background-color: #DDD;
left: .1em; left: .1em;
} }
.heroes li.selected { .heroes .text {
background-color: #CFD8DC; position: relative;
color: white; top: -3px;
}
.heroes li.selected:hover {
background-color: #BBD8DC;
color: white;
} }
.heroes .badge { .heroes .badge {
display: inline-block; display: inline-block;

View File

@ -34,7 +34,4 @@ export class HeroesComponent implements OnInit {
this.selectedHero = hero; this.selectedHero = hero;
} }
// #enddocregion on-select // #enddocregion on-select
// #docregion component
} }
// #enddocregion component

View File

@ -1,4 +1,8 @@
/* HeroesComponent's private CSS styles */ /* HeroesComponent's private CSS styles */
.selected {
background-color: #CFD8DC !important;
color: white;
}
.heroes { .heroes {
margin: 0 0 2em 0; margin: 0 0 2em 0;
list-style-type: none; list-style-type: none;
@ -15,18 +19,18 @@
height: 1.6em; height: 1.6em;
border-radius: 4px; border-radius: 4px;
} }
.heroes li.selected:hover {
background-color: #BBD8DC !important;
color: white;
}
.heroes li:hover { .heroes li:hover {
color: #607D8B; color: #607D8B;
background-color: #DDD; background-color: #DDD;
left: .1em; left: .1em;
} }
.heroes li.selected { .heroes .text {
background-color: #CFD8DC; position: relative;
color: white; top: -3px;
}
.heroes li.selected:hover {
background-color: #BBD8DC;
color: white;
} }
.heroes .badge { .heroes .badge {
display: inline-block; display: inline-block;

View File

@ -1,4 +1,8 @@
/* HeroesComponent's private CSS styles */ /* HeroesComponent's private CSS styles */
.selected {
background-color: #CFD8DC !important;
color: white;
}
.heroes { .heroes {
margin: 0 0 2em 0; margin: 0 0 2em 0;
list-style-type: none; list-style-type: none;
@ -15,18 +19,18 @@
height: 1.6em; height: 1.6em;
border-radius: 4px; border-radius: 4px;
} }
.heroes li.selected:hover {
background-color: #BBD8DC !important;
color: white;
}
.heroes li:hover { .heroes li:hover {
color: #607D8B; color: #607D8B;
background-color: #DDD; background-color: #DDD;
left: .1em; left: .1em;
} }
.heroes li.selected { .heroes .text {
background-color: #CFD8DC; position: relative;
color: white; top: -3px;
}
.heroes li.selected:hover {
background-color: #BBD8DC;
color: white;
} }
.heroes .badge { .heroes .badge {
display: inline-block; display: inline-block;
@ -39,6 +43,8 @@
left: -1px; left: -1px;
top: -4px; top: -4px;
height: 1.8em; height: 1.8em;
min-width: 16px;
text-align: right;
margin-right: .8em; margin-right: .8em;
border-radius: 4px 0 0 4px; border-radius: 4px 0 0 4px;
} }

View File

@ -1,13 +0,0 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HeroesComponent } from './heroes/heroes.component';
const routes: Routes = [
{ path: 'heroes', component: HeroesComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

View File

@ -7,7 +7,9 @@ import { RouterModule, Routes } from '@angular/router';
// #docregion import-dashboard // #docregion import-dashboard
import { DashboardComponent } from './dashboard/dashboard.component'; import { DashboardComponent } from './dashboard/dashboard.component';
// #enddocregion import-dashboard // #enddocregion import-dashboard
// #docregion heroes-route
import { HeroesComponent } from './heroes/heroes.component'; import { HeroesComponent } from './heroes/heroes.component';
// #enddocregion heroes-route
// #docregion import-herodetail // #docregion import-herodetail
import { HeroDetailComponent } from './hero-detail/hero-detail.component'; import { HeroDetailComponent } from './hero-detail/hero-detail.component';
// #enddocregion import-herodetail // #enddocregion import-herodetail
@ -37,9 +39,7 @@ const routes: Routes = [
imports: [ RouterModule.forRoot(routes) ], imports: [ RouterModule.forRoot(routes) ],
// #enddocregion ngmodule-imports // #enddocregion ngmodule-imports
// #docregion v1 // #docregion v1
// #docregion export-routermodule
exports: [ RouterModule ] exports: [ RouterModule ]
// #enddocregion export-routermodule
}) })
export class AppRoutingModule {} export class AppRoutingModule {}
// #enddocregion , v1 // #enddocregion , v1

View File

@ -23,17 +23,13 @@ import { HeroSearchComponent } from './hero-search/hero-search.component';
// #docregion v1 // #docregion v1
import { MessagesComponent } from './messages/messages.component'; import { MessagesComponent } from './messages/messages.component';
// #docregion import-httpclientmodule
@NgModule({ @NgModule({
imports: [ imports: [
// #enddocregion import-httpclientmodule
BrowserModule, BrowserModule,
FormsModule, FormsModule,
AppRoutingModule, AppRoutingModule,
// #docregion in-mem-web-api-imports // #docregion in-mem-web-api-imports
// #docregion import-httpclientmodule
HttpClientModule, HttpClientModule,
// #enddocregion import-httpclientmodule
// The HttpClientInMemoryWebApiModule module intercepts HTTP requests // The HttpClientInMemoryWebApiModule module intercepts HTTP requests
// and returns simulated server responses. // and returns simulated server responses.
@ -42,9 +38,7 @@ import { MessagesComponent } from './messages/messages.component';
InMemoryDataService, { dataEncapsulation: false } InMemoryDataService, { dataEncapsulation: false }
) )
// #enddocregion in-mem-web-api-imports // #enddocregion in-mem-web-api-imports
// #docregion import-httpclientmodule
], ],
// #enddocregion import-httpclientmodule
declarations: [ declarations: [
AppComponent, AppComponent,
DashboardComponent, DashboardComponent,
@ -56,9 +50,6 @@ import { MessagesComponent } from './messages/messages.component';
// #docregion v1 // #docregion v1
], ],
bootstrap: [ AppComponent ] bootstrap: [ AppComponent ]
// #docregion import-httpclientmodule
}) })
// #enddocregion import-httpclientmodule
export class AppModule { } export class AppModule { }
// #enddocregion , v1 // #enddocregion , v1

View File

@ -13,6 +13,11 @@ import { catchError, map, tap } from 'rxjs/operators';
import { Hero } from './hero'; import { Hero } from './hero';
import { MessageService } from './message.service'; import { MessageService } from './message.service';
// #docregion http-options
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
// #enddocregion http-options
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class HeroService { export class HeroService {
@ -21,12 +26,6 @@ export class HeroService {
private heroesUrl = 'api/heroes'; // URL to web api private heroesUrl = 'api/heroes'; // URL to web api
// #enddocregion heroesUrl // #enddocregion heroesUrl
// #docregion http-options
httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
// #enddocregion http-options
// #docregion ctor // #docregion ctor
constructor( constructor(
private http: HttpClient, private http: HttpClient,
@ -97,7 +96,7 @@ export class HeroService {
// #docregion addHero // #docregion addHero
/** POST: add a new hero to the server */ /** POST: add a new hero to the server */
addHero (hero: Hero): Observable<Hero> { addHero (hero: Hero): Observable<Hero> {
return this.http.post<Hero>(this.heroesUrl, hero, this.httpOptions).pipe( return this.http.post<Hero>(this.heroesUrl, hero, httpOptions).pipe(
tap((newHero: Hero) => this.log(`added hero w/ id=${newHero.id}`)), tap((newHero: Hero) => this.log(`added hero w/ id=${newHero.id}`)),
catchError(this.handleError<Hero>('addHero')) catchError(this.handleError<Hero>('addHero'))
); );
@ -110,7 +109,7 @@ export class HeroService {
const id = typeof hero === 'number' ? hero : hero.id; const id = typeof hero === 'number' ? hero : hero.id;
const url = `${this.heroesUrl}/${id}`; const url = `${this.heroesUrl}/${id}`;
return this.http.delete<Hero>(url, this.httpOptions).pipe( return this.http.delete<Hero>(url, httpOptions).pipe(
tap(_ => this.log(`deleted hero id=${id}`)), tap(_ => this.log(`deleted hero id=${id}`)),
catchError(this.handleError<Hero>('deleteHero')) catchError(this.handleError<Hero>('deleteHero'))
); );
@ -120,7 +119,7 @@ export class HeroService {
// #docregion updateHero // #docregion updateHero
/** PUT: update the hero on the server */ /** PUT: update the hero on the server */
updateHero (hero: Hero): Observable<any> { updateHero (hero: Hero): Observable<any> {
return this.http.put(this.heroesUrl, hero, this.httpOptions).pipe( return this.http.put(this.heroesUrl, hero, httpOptions).pipe(
tap(_ => this.log(`updated hero id=${hero.id}`)), tap(_ => this.log(`updated hero id=${hero.id}`)),
catchError(this.handleError<any>('updateHero')) catchError(this.handleError<any>('updateHero'))
); );

View File

@ -1,79 +0,0 @@
import { browser, element, by, ExpectedConditions } from 'protractor';
describe('Lazy Loading AngularJS Tests', function () {
const pageElements = {
homePageHref: element(by.cssContainingText('app-root nav a', 'Home')),
homePageParagraph: element(by.css('app-root app-home p')),
ajsUsersPageHref: element(by.cssContainingText('app-root nav a', 'Users')),
ajsUsersPageParagraph: element(by.css('app-root app-angular-js div p')),
notFoundPageHref: element(by.cssContainingText('app-root nav a', '404 Page')),
notFoundPageParagraph: element(by.css('app-root app-app404 p')),
};
beforeAll(async() => {
await browser.get('/');
});
it('should display \'Angular Home\' when visiting the home page', async() => {
await pageElements.homePageHref.click();
const paragraphText = await pageElements.homePageParagraph.getText();
expect(paragraphText).toEqual('Angular Home');
});
it('should display \'Users Page\' page when visiting the AngularJS page at /users', async() => {
await pageElements.ajsUsersPageHref.click();
await loadAngularJS();
const paragraphText = await pageElements.ajsUsersPageParagraph.getText();
expect(paragraphText).toEqual('Users Page');
});
it('should display \'Angular 404\' when visiting an invalid URL', async() => {
await pageElements.notFoundPageHref.click();
const paragraphText = await pageElements.notFoundPageParagraph.getText();
expect(paragraphText).toEqual('Angular 404');
});
// Workaround for https://github.com/angular/protractor/issues/4724
async function loadAngularJS() {
// Abort if `resumeBootstrap` has already occured
if (await browser.executeScript(`return '__TESTABILITY__NG1_APP_ROOT_INJECTOR__' in window;`)) {
return;
}
// Might have to re-insert the 'NG_DEFER_BOOTSTRAP!' if the name has been changed since protractor loaded the page
if (!await browser.executeScript('window.name.includes(\'NG_DEFER_BOOTSTRAP!\')')) {
await browser.executeScript('window.name = \'NG_DEFER_BOOTSTRAP!\' + name');
}
// Wait for the AngularJS bundle to download and initialize
await browser.wait(ExpectedConditions.presenceOf(element(by.css('app-root app-angular-js'))), 5000, 'AngularJS app');
// Run the protractor pre-bootstrap logic and resumeBootstrap
// Based on https://github.com/angular/protractor/blob/5.3.0/lib/browser.ts#L950-L969
{
let moduleNames = [];
for (const {name, script, args} of browser.mockModules_) {
moduleNames.push(name);
await browser.executeScriptWithDescription(script, 'add mock module ' + name, ...args);
}
await browser.executeScriptWithDescription(
// TODO: must manually assign __TESTABILITY__NG1_APP_ROOT_INJECTOR__ (https://github.com/angular/angular/issues/22723)
`window.__TESTABILITY__NG1_APP_ROOT_INJECTOR__ = angular.resumeBootstrap(arguments[0]) `
+ `|| angular.element('app-angular-js').injector();`,
'resume bootstrap',
moduleNames
);
}
// Wait for the initial AngularJS page to finish loading
await browser.waitForAngular();
}
});

View File

@ -1,3 +0,0 @@
{
"projectType": "cli-ajs"
}

View File

@ -1,22 +1,14 @@
import { Component, OnInit, OnDestroy, ElementRef } from '@angular/core'; import { Component, OnInit, ElementRef } from '@angular/core';
import { LazyLoaderService } from '../lazy-loader.service'; import { LazyLoaderService } from '../lazy-loader.service';
@Component({ @Component({
selector: 'app-angular-js', selector: 'app-angular-js',
template: '<div ng-view></div>' template: '<div ng-view></div>'
}) })
export class AngularJSComponent implements OnInit, OnDestroy { export class AngularJSComponent implements OnInit {
constructor( constructor(private lazyLoader: LazyLoaderService, private elRef: ElementRef) {}
private lazyLoader: LazyLoaderService,
private elRef: ElementRef
) {}
ngOnInit() { ngOnInit() {
this.lazyLoader.load(this.elRef.nativeElement); this.lazyLoader.load(this.elRef.nativeElement);
} }
ngOnDestroy() {
this.lazyLoader.destroy();
}
} }

View File

@ -19,6 +19,7 @@ import { App404Component } from './app404/app404.component';
BrowserModule, BrowserModule,
AppRoutingModule AppRoutingModule
], ],
providers: [],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { } export class AppModule { }

View File

@ -1,25 +1,23 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import * as angular from 'angular';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class LazyLoaderService { export class LazyLoaderService {
private app: angular.auto.IInjectorService; bootstrapped = false;
load(el: HTMLElement): void { load(el: HTMLElement): void {
if (this.bootstrapped) {
return;
}
import('./angularjs-app').then(app => { import('./angularjs-app').then(app => {
try { try {
this.app = app.bootstrap(el); app.bootstrap(el);
this.bootstrapped = true;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
}); });
} }
destroy() {
if (this.app) {
this.app.get('$rootScope').$destroy();
}
}
} }

View File

@ -1,181 +0,0 @@
# Accessibility in Angular
The web is used by a wide variety of people, including those who have visual or motor impairments.
A variety of assistive technologies are available that make it much easier for these groups to
interact with web-based software applications.
In addition, designing an application to be more accessible generally improves the user experience for all users.
For an in-depth introduction to issues and techniques for designing accessible applications, see the [Accessibility](https://developers.google.com/web/fundamentals/accessibility/#what_is_accessibility) section of the Google's [Web Fundamentals](https://developers.google.com/web/fundamentals/).
This page discusses best practices for designing Angular applications that
work well for all users, including those who rely on assistive technologies.
## Accessibility attributes
Building accessible web experience often involves setting [ARIA attributes](https://developers.google.com/web/fundamentals/accessibility/semantics-aria)
to provide semantic meaning where it might otherwise be missing.
Use [attribute binding](guide/template-syntax#attribute-binding) template syntax to control the values of accessibility-related attributes.
When binding to ARIA attributes in Angular, you must use the `attr.` prefix, as the ARIA
specification depends specifically on HTML attributes rather than properties on DOM elements.
```html
<!-- Use attr. when binding to an ARIA attribute -->
<button [attr.aria-label]="myActionLabel">...</button>
```
Note that this syntax is only necessary for attribute _bindings_.
Static ARIA attributes require no extra syntax.
```html
<!-- Static ARIA attributes require no extra syntax -->
<button aria-label="Save document">...</button>
```
NOTE:
<div class="alert is-helpful">
By convention, HTML attributes use lowercase names (`tabindex`), while properties use camelCase names (`tabIndex`).
See the [Template Syntax](https://angular.io/guide/template-syntax#html-attribute-vs-dom-property) guide for more background on the difference between attributes and properties.
</div>
## Angular UI components
The [Angular Material](https://material.angular.io/) library, which is maintained by the Angular team, is a suite of reusable UI components that aims to be fully accessible.
The [Component Development Kit (CDK)](https://material.angular.io/cdk/categories) includes the `a11y` package that provides tools to support various areas of accessibility.
For example:
* `LiveAnnouncer` is used to announce messages for screen-reader users using an `aria-live` region. See the W3C documentation for more information on [aria-live regions](https://www.w3.org/WAI/PF/aria-1.1/states_and_properties#aria-live).
* The `cdkTrapFocus` directive traps Tab-key focus within an element. Use it to create accessible experience for components like modal dialogs, where focus must be constrained.
For full details of these and other tools, see the [Angular CDK accessibility overview](https://material.angular.io/cdk/a11y/overview).
### Augmenting native elements
Native HTML elements capture a number of standard interaction patterns that are important to accessibility.
When authoring Angular components, you should re-use these native elements directly when possible, rather than re-implementing well-supported behaviors.
For example, instead of creating a custom element for a new variety of button, you can create a component that uses an attribute selector with a native `<button>` element.
This most commonly applies to `<button>` and `<a>`, but can be used with many other types of element.
You can see examples of this pattern in Angular Material: [`MatButton`](https://github.com/angular/components/blob/master/src/material/button/button.ts#L66-L68), [`MatTabNav`](https://github.com/angular/components/blob/master/src/material/tabs/tab-nav-bar/tab-nav-bar.ts#L67), [`MatTable`](https://github.com/angular/components/blob/master/src/material/table/table.ts#L17).
### Using containers for native elements
Sometimes using the appropriate native element requires a container element.
For example, the native `<input>` element cannot have children, so any custom text entry components need
to wrap an `<input>` with additional elements.
While you might just include the `<input>` in your custom component's template,
this makes it impossible for users of the component to set arbitrary properties and attributes to the input element.
Instead, you can create a container component that uses content projection to include the native control in the
component's API.
You can see [`MatFormField`](https://material.angular.io/components/form-field/overview) as an example of this pattern.
## Case study: Building a custom progress bar
The following example shows how to make a simple progress bar accessible by using host binding to control accessibility-related attributes.
* The component defines an accessibility-enabled element with both the standard HTML attribute `role`, and ARIA attributes. The ARIA attribute `aria-valuenow` is bound to the user's input.
```ts
import { Component, Input } from '@angular/core';
/**
* Example progressbar component.
*/
@Component({
selector: 'example-progressbar',
template: `<div class="bar" [style.width.%]="value"></div>`,
styleUrls: ['./progress-bar.css'],
host: {
// Sets the role for this component to "progressbar"
role: 'progressbar',
// Sets the minimum and maximum values for the progressbar role.
'aria-valuemin': '0',
'aria-valuemax': '0',
// Binding that updates the current value of the progressbar.
'[attr.aria-valuenow]': 'value',
}
})
export class ExampleProgressbar {
/** Current value of the progressbar. */
@Input() value: number = 0;
}
```
* In the template, the `aria-label` attribute ensures that the control is accessible to screen readers.
```html
<label>
Enter an example progress value
<input type="number" min="0" max="100"
[value]="progress" (input)="progress = $event.target.value">
</label>
<!-- The user of the progressbar sets an aria-label to communicate what the progress means. -->
<example-progressbar [value]="progress" aria-label="Example of a progress bar">
</example-progressbar>
```
[See the full example in StackBlitz](https://stackblitz.com/edit/angular-kn5jdi?file=src%2Fapp%2Fapp.component.html).
## Routing and focus management
Tracking and controlling [focus](https://developers.google.com/web/fundamentals/accessibility/focus/) in a UI is an important consideration in designing for accessibility.
When using Angular routing, you should decide where page focus goes upon navigation.
To avoid relying solely on visual cues, you need to make sure your routing code updates focus after page navigation.
Use the `NavigationEnd` event from the `Router` service to know when to update
focus.
The following example shows how to find and focus the main content header in the DOM after navigation.
```ts
router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {
const mainHeader = document.querySelector('#main-content-header')
if (mainHeader) {
mainHeader.focus();
}
});
```
In a real application, the element that receives focus will depend on your specific
application structure and layout.
The focused element should put users in a position to immediately move into the main content that has just been routed into view.
You should avoid situations where focus returns to the `body` element after a route change.
## Additional resources
* [Accessibility - Google Web Fundamentals](https://developers.google.com/web/fundamentals/accessibility)
* [ARIA specification and authoring practices](https://www.w3.org/TR/wai-aria/)
* [Material Design - Accessibility](https://material.io/design/usability/accessibility.html)
* [Smashing Magazine](https://www.smashingmagazine.com/search/?q=accessibility)
* [Inclusive Components](https://inclusive-components.design/)
* [Accessibility Resources and Code Examples](https://dequeuniversity.com/resources/)
* [W3C - Web Accessibility Initiative](https://www.w3.org/WAI/people-use-web/)
* [Rob Dodson A11ycasts](https://www.youtube.com/watch?v=HtTyRajRuyY)
* [Codelyzer](http://codelyzer.com/rules/) provides linting rules that can help you make sure your code meets accessibility standards.
Books
* "A Web for Everyone: Designing Accessible User Experiences", Sarah Horton and Whitney Quesenbery
* "Inclusive Design Patterns", Heydon Pickering

View File

@ -29,7 +29,7 @@ ng generate app-shell --client-project my-app --universal-project server-app
After running this command you will notice that the `angular.json` configuration file has been updated to add two new targets, with a few other changes. After running this command you will notice that the `angular.json` configuration file has been updated to add two new targets, with a few other changes.
<code-example format="." language="json" linenums="false"> <code-example format="." language="none" linenums="false">
"server": { "server": {
"builder": "@angular-devkit/build-angular:server", "builder": "@angular-devkit/build-angular:server",
"options": { "options": {

View File

@ -53,7 +53,7 @@ Angular supports most recent browsers. This includes the following specific vers
IE IE
</td> </td>
<td> <td>
11, 10, 9 11<br>10<br>9
</td> </td>
</tr> </tr>
<tr> <tr>
@ -89,7 +89,7 @@ Angular supports most recent browsers. This includes the following specific vers
</td> </td>
<td> <td>
Nougat (7.0), Marshmallow (6.0), Lollipop (5.0, 5.1), KitKat (4.4) Nougat (7.0)<br>Marshmallow (6.0)<br>Lollipop (5.0, 5.1)<br>KitKat (4.4)
</td> </td>
</tr> </tr>
@ -127,27 +127,25 @@ In Angular CLI version 8 and higher, applications are built using *differential
This strategy allows you to continue to build your web application to support multiple browsers, but only load the necessary code that the browser needs. This strategy allows you to continue to build your web application to support multiple browsers, but only load the necessary code that the browser needs.
For more information about how this works, see [Differential Loading](guide/deployment#differential-loading) in the [Deployment guide](guide/deployment). For more information about how this works, see [Differential Loading](guide/deployment#differential-loading) in the [Deployment guide](guide/deployment).
## Enabling polyfills with CLI projects ## Enabling polyfills
The [Angular CLI](cli) provides support for polyfills. [Angular CLI](cli) users enable polyfills through the `src/polyfills.ts` file that
If you are not using the CLI to create your projects, see [Polyfill instructions for non-CLI users](#non-cli). the CLI created with your project.
When you create a project with the `ng new` command, a `src/polyfills.ts` configuration file is created as part of your project folder.
This file incorporates the mandatory and many of the optional polyfills as JavaScript `import` statements. This file incorporates the mandatory and many of the optional polyfills as JavaScript `import` statements.
* The npm packages for the [_mandatory_ polyfills](#polyfill-libs) (such as `zone.js`) are installed automatically for you when you create your project with `ng new`, and their corresponding `import` statements are already enabled in the `src/polyfills.ts` configuration file. The npm packages for the _mandatory_ polyfills (such as `zone.js`) were installed automatically for you when you created your project and their corresponding `import` statements are ready to go. You probably won't touch these.
* If you need an _optional_ polyfill, you must install its npm package, then uncomment or create the corresponding import statement in the `src/polyfills.ts` configuration file. But if you need an optional polyfill, you'll have to install its npm package.
For example, [if you need the web animations polyfill](http://caniuse.com/#feat=web-animation), you could install it with `npm`, using the following command (or the `yarn` equivalent):
For example, if you need the optional [web animations polyfill](http://caniuse.com/#feat=web-animation), you could install it with `npm`, using the following command (or the `yarn` equivalent):
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
# install the optional web animations polyfill # note that the web-animations-js polyfill is only here as an example
# it isn't a strict requirement of Angular anymore (more below)
npm install --save web-animations-js npm install --save web-animations-js
</code-example> </code-example>
You can then add the import statement in the `src/polyfills.ts` file. Then open the `polyfills.ts` file and un-comment the corresponding `import` statement as in the following example:
For many polyfills, you can simply un-comment the corresponding `import` statement in the file, as in the following example.
<code-example header="src/polyfills.ts"> <code-example header="src/polyfills.ts">
/** /**
@ -157,14 +155,23 @@ For many polyfills, you can simply un-comment the corresponding `import` stateme
import 'web-animations-js'; // Run `npm install --save web-animations-js`. import 'web-animations-js'; // Run `npm install --save web-animations-js`.
</code-example> </code-example>
If the polyfill you want is not already in `polyfills.ts` file, add the `import` statement by hand. If you can't find the polyfill you want in `polyfills.ts`,
add it yourself, following the same pattern:
1. install the npm package
1. `import` the file in `polyfills.ts`
<div class="alert is-helpful">
Non-CLI users should follow the instructions [below](#non-cli).
</div>
{@a polyfill-libs} {@a polyfill-libs}
### Mandatory polyfills ### Mandatory polyfills
These are the polyfills required to run an Angular application on each supported browser: These are the polyfills required to run an Angular application on each supported browser:
<table> <table>
<tr style="vertical-align: top"> <tr style="vertical-align: top">
@ -182,13 +189,26 @@ These are the polyfills required to run an Angular application on each supported
<tr style="vertical-align: top"> <tr style="vertical-align: top">
<td> <td>
Chrome, Firefox, Edge, <br> Chrome, Firefox, Edge, Safari 9+
Safari, Android, IE10+
</td> </td>
<td> <td>
[ES2015](guide/browser-support#core-es6) [ES7/reflect](guide/browser-support#core-es7-reflect) (JIT only)
</td>
</tr>
<tr style="vertical-align: top">
<td>
Safari 7 & 8, IE10 & 11, Android 4.1+
</td>
<td>
[ES6](guide/browser-support#core-es6)
</td> </td>
@ -202,7 +222,7 @@ These are the polyfills required to run an Angular application on each supported
<td> <td>
ES2015<br>[classList](guide/browser-support#classlist) [ES6<br>classList](guide/browser-support#classlist)
</td> </td>
@ -215,6 +235,12 @@ These are the polyfills required to run an Angular application on each supported
Some features of Angular may require additional polyfills. Some features of Angular may require additional polyfills.
For example, the animations library relies on the standard web animation API, which is only available in Chrome and Firefox today.
(note that the dependency of web-animations-js in Angular is only necessary if `AnimationBuilder` is used.)
Here are the features which may require additional polyfills:
<table> <table>
<tr style="vertical-align: top"> <tr style="vertical-align: top">
@ -237,8 +263,31 @@ Some features of Angular may require additional polyfills.
<td> <td>
[AnimationBuilder](api/animations/AnimationBuilder). [JIT compilation](guide/aot-compiler).
(Standard animation support does not require polyfills.)
Required to reflect for metadata.
</td>
<td>
[ES7/reflect](guide/browser-support#core-es7-reflect)
</td>
<td>
All current browsers. Enabled by default.
Can remove if you always use AOT and only use Angular decorators.
</td>
</tr>
<tr style="vertical-align: top">
<td>
[Animations](guide/animations)
<br>Only if `Animation Builder` is used within the application--standard
animation support in Angular doesn't require any polyfills (as of NG6).
</td> </td>
@ -249,9 +298,8 @@ Some features of Angular may require additional polyfills.
</td> </td>
<td> <td>
<p>If AnimationBuilder is used, enables scrubbing <p>If AnimationBuilder is used then the polyfill will enable scrubbing
support for IE/Edge and Safari. support for IE/Edge and Safari (Chrome and Firefox support this natively).</p>
(Chrome and Firefox support this natively).</p>
</td> </td>
</tr> </tr>
@ -261,9 +309,14 @@ Some features of Angular may require additional polyfills.
<td> <td>
If you use the following deprecated i18n pipes: If you use the following deprecated i18n pipes:
[date](api/common/DeprecatedDatePipe), [date](api/common/DeprecatedDatePipe),
[currency](api/common/DeprecatedCurrencyPipe), [currency](api/common/DeprecatedCurrencyPipe),
[decimal](api/common/DeprecatedDecimalPipe), [decimal](api/common/DeprecatedDecimalPipe),
[percent](api/common/DeprecatedPercentPipe) [percent](api/common/DeprecatedPercentPipe)
</td> </td>
@ -284,7 +337,9 @@ Some features of Angular may require additional polyfills.
<td> <td>
[NgClass](api/common/NgClass) on SVG elements [NgClass](api/common/NgClass)
on SVG elements
</td> </td>
<td> <td>
@ -303,7 +358,9 @@ Some features of Angular may require additional polyfills.
<td> <td>
[Http](guide/http) when sending and receiving binary data [Http](guide/http)
when sending and receiving binary data
</td> </td>
<td> <td>
@ -326,8 +383,9 @@ Some features of Angular may require additional polyfills.
<td> <td>
[Router](guide/router) when using [Router](guide/router)
[hash-based routing](guide/router#appendix-locationstrategy-and-browser-url-styles)
when using [hash-based routing](guide/router#appendix-locationstrategy-and-browser-url-styles)
</td> </td>
<td> <td>
@ -346,9 +404,8 @@ Some features of Angular may require additional polyfills.
### Suggested polyfills ### Suggested polyfills ##
Below are the polyfills which are used to test the framework itself. They are a good starting point for an application.
The following polyfills are used to test the framework itself. They are a good starting point for an application.
<table> <table>
@ -369,6 +426,24 @@ The following polyfills are used to test the framework itself. They are a good s
</tr> </tr>
<tr>
<td>
<a id='core-es7-reflect' href="https://github.com/zloirock/core-js/tree/v2/fn/reflect">ES7/reflect</a>
</td>
<td>
MIT
</td>
<td>
0.5KB
</td>
</tr>
<tr> <tr>
<td> <td>
@ -391,7 +466,7 @@ The following polyfills are used to test the framework itself. They are a good s
<td> <td>
<a id='core-es6' href="https://github.com/zloirock/core-js">ES2015</a> <a id='core-es6' href="https://github.com/zloirock/core-js">ES6</a>
</td> </td>
@ -520,14 +595,11 @@ The following polyfills are used to test the framework itself. They are a good s
computed with the <a href="http://closure-compiler.appspot.com/home">closure compiler</a>. computed with the <a href="http://closure-compiler.appspot.com/home">closure compiler</a>.
{@a non-cli} {@a non-cli}
## Polyfills for non-CLI users ## Polyfills for non-CLI users
If you are not using the CLI, add your polyfill scripts directly to the host web page (`index.html`). If you are not using the CLI, you should add your polyfill scripts directly to the host web page (`index.html`), perhaps like this.
For example: <code-example header="src/index.html">
<code-example header="src/index.html" language="html" linenums="false">
&lt;!-- pre-zone polyfills --> &lt;!-- pre-zone polyfills -->
&lt;script src="node_modules/core-js/client/shim.min.js">&lt;/script> &lt;script src="node_modules/core-js/client/shim.min.js">&lt;/script>
&lt;script src="node_modules/web-animations-js/web-animations.min.js">&lt;/script> &lt;script src="node_modules/web-animations-js/web-animations.min.js">&lt;/script>

View File

@ -185,7 +185,8 @@ is available to <code>declarations</code> of this module.</p>
</td> </td>
</tr><tr> </tr><tr>
<td><code><b>@Injectable()</b><br>class MyService() {}</code></td> <td><code><b>@Injectable()</b><br>class MyService() {}</code></td>
<td><p>Declares that a class can be provided and injected by other classes. Without this decorator, the compiler won't generate enough metadata to allow the class to be created properly when it's injected somewhere.</p> <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> </td>
</tr> </tr>
</tbody></table> </tbody></table>

View File

@ -153,13 +153,16 @@ The list is by no means exhaustive, but should provide you with a good starting
(https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/): (https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/):
<code-example format="."> <code-example format=".">
RewriteEngine On RewriteEngine On
&#35 If an existing asset or directory is requested go to it as it is &#35 If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR] RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]<br> RewriteRule ^ - [L]
&#35 If the requested resource doesn't exist, use index.html &#35 If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html RewriteRule ^ /index.html
</code-example> </code-example>
@ -167,15 +170,18 @@ The list is by no means exhaustive, but should provide you with a good starting
[Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps), [Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps),
modified to serve `index.html`: modified to serve `index.html`:
``` <code-example format=".">
try_files $uri $uri/ /index.html; try_files $uri $uri/ /index.html;
```
</code-example>
* [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown * [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown
[here](http://stackoverflow.com/a/26152011/2116927): [here](http://stackoverflow.com/a/26152011/2116927):
<code-example format='.' language="xml" linenums="false"> <code-example format='.' linenums="false">
&lt;system.webServer&gt; &lt;system.webServer&gt;
&lt;rewrite&gt; &lt;rewrite&gt;
&lt;rules&gt; &lt;rules&gt;
@ -190,6 +196,7 @@ modified to serve `index.html`:
&lt;/rules&gt; &lt;/rules&gt;
&lt;/rewrite&gt; &lt;/rewrite&gt;
&lt;/system.webServer&gt; &lt;/system.webServer&gt;
</code-example> </code-example>
@ -207,11 +214,13 @@ and to
* [Firebase hosting](https://firebase.google.com/docs/hosting/): add a * [Firebase hosting](https://firebase.google.com/docs/hosting/): add a
[rewrite rule](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites). [rewrite rule](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites).
<code-example format="." language="json"> <code-example format=".">
"rewrites": [ { "rewrites": [ {
"source": "**", "source": "**",
"destination": "/index.html" "destination": "/index.html"
} ] } ]
</code-example> </code-example>
{@a cors} {@a cors}
@ -403,7 +412,7 @@ Differential loading, which is supported by default in Angular CLI version 8 and
Differential loading is a strategy where the CLI builds two separate bundles as part of your deployed application. Differential loading is a strategy where the CLI builds two separate bundles as part of your deployed application.
* The first bundle contains modern ES2015 syntax, takes advantage of built-in support in modern browsers, ships less polyfills, and results in a smaller bundle size. * The first bundle contains modern ES1015 syntax, takes advantage of built-in support in modern browsers, ships less polyfills, and results in a smaller bundle size.
* The second bundle contains code in the old ES5 syntax, along with all necessary polyfills. This results in a larger bundle size, but supports older browsers. * The second bundle contains code in the old ES5 syntax, along with all necessary polyfills. This results in a larger bundle size, but supports older browsers.
@ -437,19 +446,23 @@ When you create a production build using [`ng build --prod`](cli/build), the CLI
The `index.html` file is also modified during the build process to include script tags that enable differential loading. See the sample output below from the `index.html` file produced during a build using `ng build`. The `index.html` file is also modified during the build process to include script tags that enable differential loading. See the sample output below from the `index.html` file produced during a build using `ng build`.
<code-example language="html" format="." linenums="false"> <code-example language="html" format="." linenums="false">
&lt;body>
&lt;app-root>&lt;/app-root> <!-- ... -->
&lt;script src="runtime-es2015.js" type="module">&lt;/script> <body>
&lt;script src="runtime-es5.js" nomodule>&lt;/script> <app-root></app-root>
&lt;script src="polyfills-es2015.js" type="module">&lt;/script> <script src="runtime-es2015.js" type="module"></script>
&lt;script src="polyfills-es5.js" nomodule>&lt;/script> <script src="runtime-es5.js" nomodule></script>
&lt;script src="styles-es2015.js" type="module">&lt;/script> <script src="polyfills-es2015.js" type="module"></script>
&lt;script src="styles-es5.js" nomodule>&lt;/script> <script src="polyfills-es5.js" nomodule></script>
&lt;script src="vendor-es2015.js" type="module">&lt;/script> <script src="styles-es2015.js" type="module"></script>
&lt;script src="vendor-es5.js" nomodule>&lt;/script> <script src="styles-es5.js" nomodule></script>
&lt;script src="main-es2015.js" type="module">&lt;/script> <script src="vendor-es2015.js" type="module"></script>
&lt;script src="main-es5.js" nomodule>&lt;/script> <script src="vendor-es5.js" nomodule></script>
&lt;/body> <script src="main-es2015.js" type="module"></script>
<script src="main-es5.js" nomodule></script>
</body>
<!-- ... -->
</code-example> </code-example>
Each script tag has a `type="module"` or `nomodule` attribute. Browsers with native support for ES modules only load the scripts with the `module` type attribute and ignore scripts with the `nomodule` attribute. Legacy browsers only load the scripts with the `nomodule` attribute, and ignore the script tags with the `module` type that load ES modules. Each script tag has a `type="module"` or `nomodule` attribute. Browsers with native support for ES modules only load the scripts with the `module` type attribute and ignore scripts with the `nomodule` attribute. Legacy browsers only load the scripts with the `nomodule` attribute, and ignore the script tags with the `module` type that load ES modules.
@ -510,7 +523,7 @@ By default, legacy browsers such as IE 9-11 are ignored, and the compilation tar
<div class="alert is-important"> <div class="alert is-important">
To see which browsers are supported with the above configuration, see which settings meet to your browser support requirements, see the [Browserslist compatibility page](https://browserl.ist/?q=%3E+0.5%25%2C+last+2+versions%2C+Firefox+ESR%2C+not+dead%2C+not+IE+9-11). To see which browsers are supported with the above configuration, see which settings meet to your browser support requirements, see the [Browserslist compatibility page](https://browserl.ist/?q=%3E+0.5%25%2C+last+2+versions%2C+Firefox+ESR%2C+Chrome+41%2C+not+dead%2C+not+IE+9-11).
</div> </div>
@ -647,7 +660,7 @@ ng test --configuration es5
### Configuring the e2e command ### Configuring the e2e command
Create an [ES5 serve configuration](guide/deployment#configuring-serve-for-es5) as explained above, and configuration an ES5 configuration for the E2E target. Create an ES5 serve configuration as explained above (link to the above serve section), and configuration an ES5 configuration for the E2E target.
<code-example language="json" format="." linenums="false"> <code-example language="json" format="." linenums="false">

View File

@ -465,99 +465,3 @@ For more information about using `@angular/common/http`, see the [HttpClient gui
| `MockBackend` | [`HttpTestingController`](/api/common/http/testing/HttpTestingController) | | `MockBackend` | [`HttpTestingController`](/api/common/http/testing/HttpTestingController) |
| `MockConnection` | [`HttpTestingController`](/api/common/http/testing/HttpTestingController) | | `MockConnection` | [`HttpTestingController`](/api/common/http/testing/HttpTestingController) |
## Renderer to Renderer2 migration
### Migration Overview
The `Renderer` class has been marked as deprecated since Angular version 4. This section provides guidance on migrating from this deprecated API to the newer `Renderer2` API and what it means for your app.
### Why should I migrate to Renderer2?
The deprecated `Renderer` class has been removed in version 9 of Angular, so it's necessary to migrate to a supported API. Using `Renderer2` is the recommended strategy because it supports a similar set of functionality to `Renderer`. The API surface is quite large (with 19 methods), but the schematic should simplify this process for your applications.
### Is there action required on my end?
No. The schematic should handle most cases with the exception of `Renderer.animate()` and `Renderer.setDebugInfo()`, which already arent supported.
### What are the `__ngRendererX` methods? Why are they necessary?
Some methods either don't have exact equivalents in `Renderer2`, or they correspond to more than one expression. For example, both renderers have a `createElement()` method, but they're not equal because a call such as `renderer.createElement(parentNode, namespaceAndName)` in the `Renderer` corresponds to the following block of code in `Renderer2`:
```ts
const [namespace, name] = splitNamespace(namespaceAndName);
const el = renderer.createElement(name, namespace);
if (parentNode) {
renderer.appendChild(parentNode, el);
}
return el;
```
Migration has to guarantee that the return values of functions and types of variables stay the same. To handle the majority of cases safely, the schematic declares helper functions at the bottom of the user's file. These helpers encapsulate your own logic and keep the replacements inside your code down to a single function call. Here's an example of how the `createElement()` migration looks:
**Before:**
```ts
public createAndAppendElement() {
const el = this.renderer.createElement('span');
el.textContent = 'hello world';
return el;
}
```
**After:**
<code-example linenums=false>
public createAndAppendElement() {
const el = __ngRendererCreateElement(this.renderer, this.element, 'span');
el.textContent = 'hello world';
return el;
}
// Generated code at the bottom of the file
__ngRendererCreateElement(renderer: any, parentNode: any, nameAndNamespace: any) {
const [namespace, name] = __ngRendererSplitNamespace(namespaceAndName);
const el = renderer.createElement(name, namespace);
if (parentNode) {
renderer.appendChild(parentNode, el);
}
return el;
}
__ngRendererSplitNamespace(nameAndNamespace: any) {
// returns the split name and namespace
}
</code-example>
When implementing these helper functions, the schematic ensures that they're only declared once per file and that their names are unique enough that there's a small chance of colliding with pre-existing functions in your code. The schematic also keeps their parameter types as `any` so that it doesn't have to insert extra logic that ensures that their values have the correct type.
### Im a library author. Should I run this migration?
**Library authors should definitely use this migration to move away from the `Renderer`. Otherwise, the libraries won't work with applications built with version 9.**
### Full list of method migrations
The following table shows all methods that the migration maps from `Renderer` to `Renderer2`.
|Renderer|Renderer2|
|---|---|
|`listen(renderElement, name, callback)`|`listen(renderElement, name, callback)`|
|`setElementProperty(renderElement, propertyName, propertyValue)`|`setProperty(renderElement, propertyName, propertyValue)`|
|`setText(renderNode, text)`|`setValue(renderNode, text)`|
|`listenGlobal(target, name, callback)`|`listen(target, name, callback)`|
|`selectRootElement(selectorOrNode, debugInfo?)`|`selectRootElement(selectorOrNode)`|
|`createElement(parentElement, name, debugInfo?)`|`appendChild(parentElement, createElement(name))`|
|`setElementStyle(el, style, value?)`|`value == null ? removeStyle(el, style) : setStyle(el, style, value)`
|`setElementAttribute(el, name, value?)`|`attributeValue == null ? removeAttribute(el, name) : setAttribute(el, name, value)`
|`createText(parentElement, value, debugInfo?)`|`appendChild(parentElement, createText(value))`|
|`createTemplateAnchor(parentElement)`|`appendChild(parentElement, createComment(''))`|
|`setElementClass(renderElement, className, isAdd)`|`isAdd ? addClass(renderElement, className) : removeClass(renderElement, className)`|
|`projectNodes(parentElement, nodes)`|`for (let i = 0; i < nodes.length; i<ins></ins>) { appendChild(parentElement, nodes<i>); }`|
|`attachViewAfter(node, viewRootNodes)`|`const parentElement = parentNode(node); const nextSibling = nextSibling(node); for (let i = 0; i < viewRootNodes.length; i<ins></ins>) { insertBefore(parentElement, viewRootNodes<i>, nextSibling);}`|
|`detachView(viewRootNodes)`|`for (let i = 0; i < viewRootNodes.length; i<ins></ins>) {const node = viewRootNodes<i>; const parentElement = parentNode(node); removeChild(parentElement, node);}`|
|`destroyView(hostElement, viewAllNodes)`|`for (let i = 0; i < viewAllNodes.length; i<ins></ins>) { destroyNode(viewAllNodes<i>); }`|
|`setBindingDebugInfo()`|This function is a noop in `Renderer2`.|
|`createViewRoot(hostElement)`|Should be replaced with a reference to `hostElement`|
|`invokeElementMethod(renderElement, methodName, args?)`|`(renderElement as any)<methodName>.apply(renderElement, args);`|
|`animate(element, startingStyles, keyframes, duration, delay, easing, previousPlayers?)`|Throws an error (same behavior as `Renderer.animate()`)|

View File

@ -1,5 +1,12 @@
# Entry Components # Entry Components
#### Prerequisites:
A basic understanding of the following concepts:
* [Bootstrapping](guide/bootstrapping).
<hr />
An entry component is any component that Angular loads imperatively, (which means youre not referencing it in the template), by type. You specify an entry component by bootstrapping it in an NgModule, or including it in a routing definition. An entry component is any component that Angular loads imperatively, (which means youre not referencing it in the template), by type. You specify an entry component by bootstrapping it in an NgModule, or including it in a routing definition.
<div class="alert is-helpful"> <div class="alert is-helpful">

View File

@ -2,6 +2,12 @@
Feature modules are NgModules for the purpose of organizing code. Feature modules are NgModules for the purpose of organizing code.
#### Prerequisites
A basic understanding of the following:
* [Bootstrapping](guide/bootstrapping).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
For the final sample app with a feature module that this page describes, For the final sample app with a feature module that this page describes,
see the <live-example></live-example>. see the <live-example></live-example>.

View File

@ -1,5 +1,12 @@
# Frequently Used Modules # Frequently Used Modules
#### Prerequisites
A basic understanding of [Bootstrapping](guide/bootstrapping).
<hr>
An Angular app needs at least one module that serves as the root module. An Angular app needs at least one module that serves as the root module.
As you add features to your app, you can add them in modules. As you add features to your app, you can add them in modules.
The following are frequently used Angular modules with examples The following are frequently used Angular modules with examples

View File

@ -454,9 +454,10 @@ A form of property [data binding](#data-binding) in which a [template expression
That text can be concatenated with neighboring text before it is assigned to an element property That text can be concatenated with neighboring text before it is assigned to an element property
or displayed between element tags, as in this example. or displayed between element tags, as in this example.
```html <code-example language="html" escape="html">
<label>My current hero is {{hero.name}}</label> <label>My current hero is {{hero.name}}</label>
```
</code-example>
Read more about [interpolation](guide/template-syntax#interpolation) in [Template Syntax](guide/template-syntax). Read more about [interpolation](guide/template-syntax#interpolation) in [Template Syntax](guide/template-syntax).

View File

@ -1,13 +1,23 @@
# Lazy Loading Feature Modules # Lazy Loading Feature Modules
#### Prerequisites
A basic understanding of the following:
* [Feature Modules](guide/feature-modules).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
* [Types of Feature Modules](guide/module-types).
* [Routing and Navigation](guide/router).
For the final sample app with two lazy loaded modules that this page describes, see the
<live-example></live-example>.
<hr>
## High level view ## High level view
By default, NgModules are eagerly loaded, which means that as soon as the app loads, so do all the NgModules, whether or not they are immediately necessary. For large apps with lots of routes, consider lazy loading&mdash;a design pattern that loads NgModules as needed. Lazy loading helps keep initial By default, NgModules are eagerly loaded, which means that as soon as the app loads, so do all the NgModules, whether or not they are immediately necessary. For large apps with lots of routes, consider lazy loading&mdash;a design pattern that loads NgModules as needed. Lazy loading helps keep initial
bundle sizes smaller, which in turn helps decrease load times. bundle sizes smaller, which in turn helps decrease load times.
For the final sample app with two lazy loaded modules that this page describes, see the
<live-example></live-example>.
There are three main steps to setting up a lazy loaded feature module: There are three main steps to setting up a lazy loaded feature module:
1. Create the feature module. 1. Create the feature module.

View File

@ -1,5 +1,16 @@
# Types of Feature Modules # Types of Feature Modules
#### Prerequisites
A basic understanding of the following concepts:
* [Feature Modules](guide/feature-modules).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
<hr>
There are five general categories of feature modules which There are five general categories of feature modules which
tend to fall into the following groups: tend to fall into the following groups:

View File

@ -1,5 +1,15 @@
# NgModule API # NgModule API
#### Prerequisites
A basic understanding of the following concepts:
* [Bootstrapping](guide/bootstrapping).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
<hr />
## Purpose of `@NgModule`
At a high level, NgModules are a way to organize Angular apps At a high level, NgModules are a way to organize Angular apps
and they accomplish this through the metadata in the `@NgModule` and they accomplish this through the metadata in the `@NgModule`
decorator. decorator.

View File

@ -1,5 +1,13 @@
# NgModule FAQs # NgModule FAQs
#### Prerequisites:
A basic understanding of the following concepts:
* [NgModules](guide/ngmodules).
<hr />
NgModules help organize an application into cohesive blocks of functionality. NgModules help organize an application into cohesive blocks of functionality.
This page answers the questions many developers ask about NgModule design and implementation. This page answers the questions many developers ask about NgModule design and implementation.

View File

@ -1,9 +1,13 @@
# JavaScript Modules vs. NgModules # JavaScript Modules vs. NgModules
#### Prerequisites
A basic understanding of [JavaScript/ECMAScript modules](https://hacks.mozilla.org/2015/08/es6-in-depth-modules/).
<hr>
JavaScript and Angular use modules to organize code, and JavaScript and Angular use modules to organize code, and
though they organize it differently, Angular apps rely on both. though they organize it differently, Angular apps rely on both.
## JavaScript modules ## JavaScript modules
In JavaScript, modules are individual files with JavaScript code in them. To make whats in them available, you write an export statement, usually after the relevant code, like this: In JavaScript, modules are individual files with JavaScript code in them. To make whats in them available, you write an export statement, usually after the relevant code, like this:
@ -20,8 +24,6 @@ import { AppComponent } from './app.component';
JavaScript modules help you namespace, preventing accidental global variables. JavaScript modules help you namespace, preventing accidental global variables.
For more information on JavaScript modules, see [JavaScript/ECMAScript modules](https://hacks.mozilla.org/2015/08/es6-in-depth-modules/).
## NgModules ## NgModules
<!-- KW-- perMisko: let's discuss. This does not answer the question why it is different. Also, last sentence is confusing.--> <!-- KW-- perMisko: let's discuss. This does not answer the question why it is different. Also, last sentence is confusing.-->

View File

@ -1,5 +1,13 @@
# NgModules # NgModules
#### Prerequisites
A basic understanding of the following concepts:
* [Bootstrapping](guide/bootstrapping).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
<hr>
**NgModules** configure the injector and the compiler and help organize related things together. **NgModules** configure the injector and the compiler and help organize related things together.
An NgModule is a class marked by the `@NgModule` decorator. An NgModule is a class marked by the `@NgModule` decorator.
@ -12,6 +20,7 @@ For an example app showcasing all the techniques that NgModules related pages
cover, see the <live-example></live-example>. For explanations on the individual techniques, visit the relevant NgModule pages under the NgModules cover, see the <live-example></live-example>. For explanations on the individual techniques, visit the relevant NgModule pages under the NgModules
section. section.
## Angular modularity ## Angular modularity
Modules are a great way to organize an application and extend it with capabilities from external libraries. Modules are a great way to organize an application and extend it with capabilities from external libraries.
@ -48,13 +57,12 @@ You then import these modules into the root module.
## The basic NgModule ## The basic NgModule
The [Angular CLI](cli) generates the following basic `AppModule` when creating a new app. The [Angular CLI](cli) generates the following basic app module when creating a new app.
<code-example path="bootstrapping/src/app/app.module.ts" region="whole-ngmodule" header="src/app/app.module.ts" linenums="false">
<code-example path="ngmodules/src/app/app.module.1.ts" header="src/app/app.module.ts (default AppModule)" linenums="false"> // @NgModule decorator with its metadata
</code-example> </code-example>
At the top are the import statements. The next section is where you configure the `@NgModule` by stating what components and directives belong to it (`declarations`) as well as which other modules it uses (`imports`). For more information on the structure of an `@NgModule`, be sure to read [Bootstrapping](guide/bootstrapping). At the top are the import statements. The next section is where you configure the `@NgModule` by stating what components and directives belong to it (`declarations`) as well as which other modules it uses (`imports`). This page builds on [Bootstrapping](guide/bootstrapping), which covers the structure of an NgModule in detail. If you need more information on the structure of an `@NgModule`, be sure to read [Bootstrapping](guide/bootstrapping).
<hr /> <hr />

View File

@ -1,10 +1,16 @@
# Providers # Providers
A provider is an instruction to the DI system on how to obtain a value for a dependency. Most of the time, these dependencies are services that you create and provide. #### Prerequisites:
* A basic understanding of [Bootstrapping](guide/bootstrapping).
* Familiarity with [Frequently Used Modules](guide/frequent-ngmodules).
For the final sample app using the provider that this page describes, For the final sample app using the provider that this page describes,
see the <live-example></live-example>. see the <live-example></live-example>.
<hr>
A provider is an instruction to the DI system on how to obtain a value for a dependency. Most of the time, these dependencies are services that you create and provide.
## Providing a service ## Providing a service
If you already have an app that was created with the [Angular CLI](cli), you can create a service using the [`ng generate`](cli/generate) CLI command in the root project directory. Replace _User_ with the name of your service. If you already have an app that was created with the [Angular CLI](cli), you can create a service using the [`ng generate`](cli/generate) CLI command in the root project directory. Replace _User_ with the name of your service.

View File

@ -1,5 +1,18 @@
# Sharing Modules # Sharing Modules
#### Prerequisites
A basic understanding of the following:
* [Feature Modules](guide/feature-modules).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
* [Routing and Navigation](guide/router).
* [Lazy loading modules](guide/lazy-loading-ngmodules).
<!--* Components (#TBD) We dont have a page just on the concept of components, but I think one would be helpful for beginners.-->
<hr>
Creating shared modules allows you to organize and streamline your code. You can put commonly Creating shared modules allows you to organize and streamline your code. You can put commonly
used directives, pipes, and components into one module and then import just that module wherever used directives, pipes, and components into one module and then import just that module wherever
you need it in other parts of your app. you need it in other parts of your app.
@ -41,7 +54,7 @@ to import `FormsModule`, `SharedModule` can still export
way, you can give other modules access to `FormsModule` without way, you can give other modules access to `FormsModule` without
having to import it directly into the `@NgModule` decorator. having to import it directly into the `@NgModule` decorator.
### Using components vs services from other modules ### Using components vs services from other modules.
There is an important distinction between using another module's component and There is an important distinction between using another module's component and
using a service from another module. Import modules when you want to use using a service from another module. Import modules when you want to use

View File

@ -1,10 +1,15 @@
# Singleton services # Singleton services
A singleton service is a service for which only once instance exists in an app. #### Prerequisites:
* A basic understanding of [Bootstrapping](guide/bootstrapping).
* Familiarity with [Providers](guide/providers).
For a sample app using the app-wide singleton service that this page describes, see the For a sample app using the app-wide singleton service that this page describes, see the
<live-example name="ngmodules"></live-example> showcasing all the documented features of NgModules. <live-example name="ngmodules"></live-example> showcasing all the documented features of NgModules.
<hr />
## Providing a singleton service ## Providing a singleton service
There are two ways to make a service a singleton in Angular: There are two ways to make a service a singleton in Angular:

View File

@ -156,12 +156,3 @@ In Angular version 9 and later, it will be safe to remove any `{static: false}`
Yes, absolutely! Yes, absolutely!
Because we have not changed the default query behavior in version 8 (i.e. the compiler still chooses a timing if no flag is set), when your application runs with a library that has not updated to version 8, the library will run the same way it did in version 7. Because we have not changed the default query behavior in version 8 (i.e. the compiler still chooses a timing if no flag is set), when your application runs with a library that has not updated to version 8, the library will run the same way it did in version 7.
This guarantees your app will work in version 8 even if libraries take longer to update their code. This guarantees your app will work in version 8 even if libraries take longer to update their code.
{@a update-library-to-use-static-flag}
### Can I update my library to version 8 by adding the `static` flag to view queries, while still being compatible with Angular version 7 apps?
Yes, the Angular team's recommendation for libraries is to update to version 8 and add the `static` flag. Angular version 7 apps will continue to work with libraries that have this flag.
However, if you update your library to Angular version 8 and want to take advantage of the new version 8 APIs, or you want more recent dependencies (such as Typescript or RxJS) your library will become incompatible with Angular version 7 apps. If your goal is to make your library compatible with Angular versions 7 and 8, you should not update your lib at all—except for `peerDependencies` in `package.json`.
In general, the most efficient plan is for libraries to adopt a 6 month major version schedule and bump the major version after each Angular update. That way, libraries stay in the same release cadence as Angular.

View File

@ -275,179 +275,53 @@ In this example, the `[ngClass]="odd"` stays on the `<div>`.
{@a microsyntax} {@a microsyntax}
## Microsyntax ### Microsyntax
The Angular microsyntax lets you configure a directive in a compact, friendly string. The Angular microsyntax lets you configure a directive in a compact, friendly string.
The microsyntax parser translates that string into attributes on the `<ng-template>`: The microsyntax parser translates that string into attributes on the `<ng-template>`:
* The `let` keyword declares a [_template input variable_](guide/structural-directives#template-input-variable) * The `let` keyword declares a [_template input variable_](guide/structural-directives#template-input-variable)
that you reference within the template. The input variables in this example are `hero`, `i`, and `odd`. that you reference within the template. The input variables in this example are `hero`, `i`, and `odd`.
The parser translates `let hero`, `let i`, and `let odd` into variables named The parser translates `let hero`, `let i`, and `let odd` into variables named,
`let-hero`, `let-i`, and `let-odd`. `let-hero`, `let-i`, and `let-odd`.
* The microsyntax parser title-cases all directives and prefixes them with the directive's * The microsyntax parser takes `of` and `trackBy`, title-cases them (`of` -> `Of`, `trackBy` -> `TrackBy`),
attribute name, such as `ngFor`. For example, the `ngFor` input properties, and prefixes them with the directive's attribute name (`ngFor`), yielding the names `ngForOf` and `ngForTrackBy`.
`of` and `trackBy`, become `ngForOf` and `ngForTrackBy`, respectively. Those are the names of two `NgFor` _input properties_ .
That's how the directive learns that the list is `heroes` and the track-by function is `trackById`. That's how the directive learns that the list is `heroes` and the track-by function is `trackById`.
* As the `NgFor` directive loops through the list, it sets and resets properties of its own _context_ object. * As the `NgFor` directive loops through the list, it sets and resets properties of its own _context_ object.
These properties can include, but aren't limited to, `index`, `odd`, and a special property These properties include `index` and `odd` and a special property named `$implicit`.
named `$implicit`.
* The `let-i` and `let-odd` variables were defined as `let i=index` and `let odd=odd`. * The `let-i` and `let-odd` variables were defined as `let i=index` and `let odd=odd`.
Angular sets them to the current value of the context's `index` and `odd` properties. Angular sets them to the current value of the context's `index` and `odd` properties.
* The context property for `let-hero` wasn't specified. * The context property for `let-hero` wasn't specified.
Its intended source is implicit. Its intended source is implicit.
Angular sets `let-hero` to the value of the context's `$implicit` property, Angular sets `let-hero` to the value of the context's `$implicit` property
which `NgFor` has initialized with the hero for the current iteration. which `NgFor` has initialized with the hero for the current iteration.
* The [`NgFor` API guide](api/common/NgForOf "API: NgFor") * The [API guide](api/common/NgForOf "API: NgFor")
describes additional `NgFor` directive properties and context properties. describes additional `NgFor` directive properties and context properties.
* The `NgForOf` directive implements `NgFor`. Read more about additional `NgForOf` directive properties and context properties in the [NgForOf API reference](api/common/NgForOf). * `NgFor` is implemented by the `NgForOf` directive. Read more about additional `NgForOf` directive properties and context properties [NgForOf API reference](api/common/NgForOf).
### Writing your own structural directives
These microsyntax mechanisms are also available to you when you write your own structural directives.
For example, microsyntax in Angular allows you to write `<div *ngFor="let item of items">{{item}}</div>`
instead of `<ng-template ngFor [ngForOf]="items"><div>{{item}}</div></ng-template`.
The following sections provide detailed information on constraints, grammar,
and translation of microsyntax.
### Constraints
Microsyntax must meet the following requirements:
- It must be known ahead of time so that IDEs can parse it without knowing the underlying semantics of the directive or what directives are present.
- It must translate to key-value attributes in the DOM.
### Grammar
When you write your own structural directives, use the following grammar:
```
*:prefix="( :let | :expression ) (';' | ',')? ( :let | :as | :keyExp )*"
```
The following tables describe each portion of the microsyntax grammar.
<!-- What should I put in the table headers? -->
<table>
<tr>
<th></th>
<th></th>
</tr>
<tr>
<td><code>prefix</code></td>
<td>HTML attribute key</td>
</tr>
<tr>
<td><code>key</code></td>
<td>HTML attribute key</td>
</tr>
<tr>
<td><code>local</code></td>
<td>local variable name used in the template</td>
</tr>
<tr>
<td><code>export</code></td>
<td>value exported by the directive under a given name</td>
</tr>
<tr>
<td><code>expression</code></td>
<td>standard Angular expression</td>
</tr>
</table>
<!-- The items in this table seem different. Is there another name for how we should describe them? -->
<table>
<tr>
<th></th>
</tr>
<tr>
<td colspan="3"><code>keyExp = :key ":"? :expression ("as" :local)? ";"? </code></td>
</tr>
<tr>
<td colspan="3"><code>let = "let" :local "=" :export ";"?</code></td>
</tr>
<tr>
<td colspan="3"><code>as = :export "as" :local ";"?</code></td>
</tr>
</table>
### Translation These microsyntax mechanisms are available to you when you write your own structural directives.
A microsyntax is translated to the normal binding syntax as follows:
<!-- What to put in the table headers below? Are these correct?-->
<table>
<tr>
<th>Microsyntax</th>
<th>Translation</th>
</tr>
<tr>
<td><code>prefix</code> and naked <code>expression</code></td>
<td><code>[prefix]="expression"</code></td>
</tr>
<tr>
<td><code>keyExp</code></td>
<td><code>[prefixKey] "expression"
(let-prefixKey="export")</code>
<br />
Notice that the <code>prefix</code>
is added to the <code>key</code>
</td>
</tr>
<tr>
<td><code>let</code></td>
<td><code>let-local="export"</code></td>
</tr>
</table>
### Microsyntax examples
The following table demonstrates how Angular desugars microsyntax.
<table>
<tr>
<th>Microsyntax</th>
<th>Desugared</th>
</tr>
<tr>
<td><code>*ngFor="let item of [1,2,3]"</code></td>
<td><code>&lt;ng-template ngFor let-item [ngForOf]="[1,2,3]"&gt;</code></td>
</tr>
<tr>
<td><code>*ngFor="let item of [1,2,3] as items; trackBy: myTrack; index as i"</code></td>
<td><code>&lt;ng-template ngFor let-item [ngForOf]="[1,2,3]" let-items="ngForOf" [ngForTrackBy]="myTrack" let-i="index"&gt;</code>
</td>
</tr>
<tr>
<td><code>*ngIf="exp"</code></td>
<td><code>&lt;ng-template [ngIf]="exp"&gt;</code></td>
</tr>
<tr>
<td><code>*ngIf="exp as value"</code></td>
<td><code>&lt;ng-template [ngIf]="exp" let-value="ngIf"&gt;</code></td>
</tr>
</table>
Studying the Studying the
[source code for `NgIf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts "Source: NgIf") [source code for `NgIf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts "Source: NgIf")
and [`NgForOf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts "Source: NgForOf") and [`NgForOf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts "Source: NgForOf")
is a great way to learn more. is a great way to learn more.
{@a template-input-variable} {@a template-input-variable}
{@a template-input-variables} {@a template-input-variables}
## Template input variable ### Template input variable
A _template input variable_ is a variable whose value you can reference _within_ a single instance of the template. A _template input variable_ is a variable whose value you can reference _within_ a single instance of the template.
There are several such variables in this example: `hero`, `i`, and `odd`. There are several such variables in this example: `hero`, `i`, and `odd`.
@ -472,7 +346,7 @@ variable as the `hero` declared as `#hero`.
{@a one-per-element} {@a one-per-element}
## One structural directive per host element ### One structural directive per host element
Someday you'll want to repeat a block of HTML but only when a particular condition is true. Someday you'll want to repeat a block of HTML but only when a particular condition is true.
You'll _try_ to put both an `*ngFor` and an `*ngIf` on the same host element. You'll _try_ to put both an `*ngFor` and an `*ngIf` on the same host element.

View File

@ -1796,7 +1796,7 @@ Though `@Input()` and `@Output()` often appear together in apps, you can use
them separately. If the nested them separately. If the nested
component is such that it only needs to send data to its parent, you wouldn't component is such that it only needs to send data to its parent, you wouldn't
need an `@Input()`, only an `@Output()`. The reverse is also true in that if the need an `@Input()`, only an `@Output()`. The reverse is also true in that if the
child only needs to receive data from the parent, you'd only need `@Input()`. child only needs to receive data from the parent, you'd only neeed `@Input()`.
</div> </div>
@ -2063,14 +2063,14 @@ to declare inputs and outputs, you can identify
members in the `inputs` and `outputs` arrays members in the `inputs` and `outputs` arrays
of the directive metadata, as in this example: of the directive metadata, as in this example:
<code-example path="inputs-outputs/src/app/in-the-metadata/in-the-metadata.component.ts" region="metadata" header="src/app/in-the-metadata/in-the-metadata.component.ts" linenums="false"> <code-example path="inputs-outputs/src/app/in-the-metadata/in-the-metadata.component.ts" region="metadata" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
While declaring `inputs` and `outputs` in the `@Directive` and `@Component` While declaring `inputs` and `outputs` in the `@Directive` and `@Component`
metadata is possible, it is a better practice to use the `@Input()` and `@Output()` metadata is possible, it is a better practice to use the `@Input()` and `@Output()`
class decorators instead, as follows: class decorators instead, as follows:
<code-example path="inputs-outputs/src/app/input-output/input-output.component.ts" region="input-output" header="src/app/input-output/input-output.component.ts" linenums="false"> <code-example path="inputs-outputs/src/app/input-output/input-output.component.ts" region="input-output" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
See the [Decorate input and output properties](guide/styleguide#decorate-input-and-output-properties) section of the See the [Decorate input and output properties](guide/styleguide#decorate-input-and-output-properties) section of the
@ -2104,7 +2104,7 @@ offer a solution.
Alias inputs and outputs in the metadata using a colon-delimited (`:`) string with Alias inputs and outputs in the metadata using a colon-delimited (`:`) string with
the directive property name on the left and the public alias on the right: the directive property name on the left and the public alias on the right:
<code-example path="inputs-outputs/src/app/aliasing/aliasing.component.ts" region="alias" header="src/app/aliasing/aliasing.component.ts" linenums="false"> <code-example path="inputs-outputs/src/app/aliasing/aliasing.component.ts" region="alias" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -2112,7 +2112,7 @@ the directive property name on the left and the public alias on the right:
You can specify the alias for the property name by passing the alias name to the `@Input()`/`@Output()` decorator. The internal name remains as usual. You can specify the alias for the property name by passing the alias name to the `@Input()`/`@Output()` decorator. The internal name remains as usual.
<code-example path="inputs-outputs/src/app/aliasing/aliasing.component.ts" region="alias-input-output" header="src/app/aliasing/aliasing.component.ts" linenums="false"> <code-example path="inputs-outputs/src/app/aliasing/aliasing.component.ts" region="alias-input-output" header="src/app/app.component.html" linenums="false">
</code-example> </code-example>
@ -2273,27 +2273,3 @@ the component.
</code-example> </code-example>
The `$any()` cast function works anywhere in a binding expression where a method call is valid. The `$any()` cast function works anywhere in a binding expression where a method call is valid.
## SVG in templates
It is possible to use SVG as valid templates in Angular. All of the template syntax below is
applicable to both SVG and HTML. Learn more in the SVG [1.1](https://www.w3.org/TR/SVG11/) and
[2.0](https://www.w3.org/TR/SVG2/) specifications.
Why would you use SVG as template, instead of simply adding it as image to your application?
When you use an SVG as the template, you are able to use directives and bindings just like with HTML
templates. This means that you will be able to dynamically generate interactive graphics.
Refer to the sample code snippet below for a syntax example:
<code-example path="template-syntax/src/app/svg.component.ts" header="src/app/svg.component.ts">
</code-example>
Add the below code to your `svg.component.svg` file:
<code-example path="template-syntax/src/app/svg.component.svg" header="src/app/svg.component.svg">
</code-example>
Here you can see the use of a `click()` event binding and the property binding syntax
(`[attr.fill]="fillColor"`).

View File

@ -868,8 +868,6 @@ As of Angular version 8, lazy loading code can be accomplished simply by using t
The service uses the `import()` method to load your bundled AngularJS application lazily. This decreases the initial bundle size of your application as you're not loading code your user doesn't need yet. You also need to provide a way to _bootstrap_ the application manually after it has been loaded. AngularJS provides a way to manually bootstrap an application using the [angular.bootstrap()](https://docs.angularjs.org/api/ng/function/angular.bootstrap) method with a provided HTML element. Your AngularJS app should also expose a `bootstrap` method that bootstraps the AngularJS app. The service uses the `import()` method to load your bundled AngularJS application lazily. This decreases the initial bundle size of your application as you're not loading code your user doesn't need yet. You also need to provide a way to _bootstrap_ the application manually after it has been loaded. AngularJS provides a way to manually bootstrap an application using the [angular.bootstrap()](https://docs.angularjs.org/api/ng/function/angular.bootstrap) method with a provided HTML element. Your AngularJS app should also expose a `bootstrap` method that bootstraps the AngularJS app.
To ensure any necessary teardown is triggered in the AngularJS app, such as removal of global listeners, you also implement a method to call the `$rootScope.destroy()` method.
<code-example path="upgrade-lazy-load-ajs/src/app/angularjs-app/index.ts" header="angularjs-app"> <code-example path="upgrade-lazy-load-ajs/src/app/angularjs-app/index.ts" header="angularjs-app">
</code-example> </code-example>
@ -888,7 +886,7 @@ In your Angular application, you need a component as a placeholder for your Angu
<code-example path="upgrade-lazy-load-ajs/src/app/angular-js/angular-js.component.ts" header="src/app/angular-js/angular-js.component.ts"> <code-example path="upgrade-lazy-load-ajs/src/app/angular-js/angular-js.component.ts" header="src/app/angular-js/angular-js.component.ts">
</code-example> </code-example>
When the Angular Router matches a route that uses AngularJS, the `AngularJSComponent` is rendered, and the content is rendered within the AngularJS [`ng-view`](https://docs.angularjs.org/api/ngRoute/directive/ngView) directive. When the user navigates away from the route, the `$rootScope` is destroyed on the AngularJS application. When the Angular Router matches a route that uses AngularJS, the `AngularJSComponent` is rendered, and the content is rendered within the AngularJS [`ng-view`](https://docs.angularjs.org/api/ngRoute/directive/ngView) directive.
### Configure a custom route matcher for AngularJS routes ### Configure a custom route matcher for AngularJS routes

View File

@ -27,7 +27,7 @@ Running this command will:
// Create a new // Create a new
const worker = new Worker('./app.worker', { type: 'module' }); const worker = new Worker('./app.worker', { type: 'module' });
worker.onmessage = ({ data }) => { worker.onmessage = ({ data }) => {
console.log(`page got message: ${data}`); console.log('page got message: $\{data\}');
}; };
worker.postMessage('hello'); worker.postMessage('hello');
} else { } else {

View File

@ -157,7 +157,7 @@ The JSON schemas that the define the options and defaults for each of these defa
### Alternate build configurations ### Alternate build configurations
By default, a `production` configuration is defined, and the `ng build` command has `--prod` option that builds using this configuration. The `production` configuration sets defaults that optimize the app in a number of ways, such as bundling files, minimizing excess whitespace, removing comments and dead code, and rewriting code to use short, cryptic names ("minification"). By default, a `production` configuration is defined, and the `ng build` command has `--prod` option that builds using this configuration. The `production` configuration sets defaults that optimize the app in a number of ways, such bundling files, minimizing excess whitespace, removing comments and dead code, and rewriting code to use short, cryptic names ("minification").
You can define and name additional alternate configurations (such as `stage`, for instance) appropriate to your development process. Some examples of different build configurations are `stable`, `archive` and `next` used by AIO itself, and the individual locale-specific configurations required for building localized versions of an app. For details, see [Internationalization (i18n)](guide/i18n#merge-aot). You can define and name additional alternate configurations (such as `stage`, for instance) appropriate to your development process. Some examples of different build configurations are `stable`, `archive` and `next` used by AIO itself, and the individual locale-specific configurations required for building localized versions of an app. For details, see [Internationalization (i18n)](guide/i18n#merge-aot).
@ -227,107 +227,3 @@ The following example uses the `ignore` field to exclude certain files in the as
{ "glob": "**/*", "input": "src/assets/", "ignore": ["**/*.svg"], "output": "/assets/" }, { "glob": "**/*", "input": "src/assets/", "ignore": ["**/*.svg"], "output": "/assets/" },
] ]
</code-example> </code-example>
{@a style-script-config}
### Styles and scripts configuration
An array entry for the `styles` and `scripts` options can be a simple path string, or an object that points to an extra entry-point file.
The associated builder will load that file and its dependencies as a separate bundle during the build.
With a configuration object, you have the option of naming the bundle for the entry point, using a `bundleName` field.
The bundle is injected by default, but you can set `inject` to false to exclude the bundle from injection.
For example, the following object values create and name a bundle that contains styles and scripts, and excludes it from injection:
<code-example format="." language="json" linenums="false">
"styles": [
{ "input": "src/external-module/styles.scss", "inject": false, "bundleName": "external-module" }
],
"scripts": [
{ "input": "src/external-module/main.js", "inject": false, "bundleName": "external-module" }
]
</code-example>
You can mix simple and complex file references for styles and scripts.
<code-example format="." language="json" linenums="false">
"styles": [
"src/styles.css",
"src/more-styles.css",
{ "input": "src/lazy-style.scss", "inject": false },
{ "input": "src/pre-rename-style.scss", "bundleName": "renamed-style" },
]
</code-example>
{@a style-preprocessor}
#### Style preprocessor options
In Sass and Stylus you can make use of the `includePaths` functionality for both component and global styles, which allows you to add extra base paths that will be checked for imports.
To add paths, use the `stylePreprocessorOptions` option:
<code-example format="." language="json" linenums="false">
"stylePreprocessorOptions": {
"includePaths": [
"src/style-paths"
]
}
</code-example>
Files in that folder, such as `src/style-paths/_variables.scss`, can be imported from anywhere in your project without the need for a relative path:
```ts
// src/app/app.component.scss
// A relative path works
@import '../style-paths/variables';
// But now this works as well
@import 'variables';
```
Note that you will also need to add any styles or scripts to the `test` builder if you need them for unit tests.
See also [Using runtime-global libraries inside your app](guide/using-libraries#using-runtime-global-libraries-inside-your-app).
{@a optimize-and-srcmap}
### Optimization and source map configuration
The `optimization` and `sourceMap` command options are simple Boolean flags.
You can supply an object as a configuration value for either of these to provide more detailed instruction.
* The flag `--optimization="true"` applies to both scripts and styles. You can supply a value such as the following to apply optimization to one or the other:
<code-example format="." language="json" linenums="false">
"optimization": { "scripts": true, "styles": false }
</code-example>
* The flag `--sourceMap="true"` outputs source maps for both scripts and styles.
You can configure the option to apply to one or the other.
You can also choose to output hidden source maps, or resolve vendor package source maps.
For example:
<code-example format="." language="json" linenums="false">
"sourceMaps": { "scripts": true, "styles": false, "hidden": true, "vendor": true }
</code-example>
<div class="alert is-helpful">
When using hidden source maps, source maps will not be referenced in the bundle.
These are useful if you only want source maps to map error stack traces in error reporting tools,
but don't want to expose your source maps in the browser developer tools.
For [Universal](guide/glossary#universal), you can reduce the code rendered in the HTML page by
setting styles optimization to `true` and styles source maps to `false`.
</div>

View File

@ -34,12 +34,23 @@
"url": "https://dev.to/t/angular", "url": "https://dev.to/t/angular",
"rev": true, "rev": true,
"title": "DEV Community" "title": "DEV Community"
}
}
}, },
"angular-in-depth" : { "Groups": {
"desc": "The place where advanced Angular concepts are explained", "order": 2,
"url": "https://blog.angularindepth.com", "resources": {
"sldkjfslkjfslkjdsklj": {
"desc": "Meetup in Barcelona, Spain. Express your motivations, share your ideas and play together creating awesome things in team.",
"rev": true, "rev": true,
"title": "Angular In Depth" "title": "Angular Beers",
"url": "http://www.meetup.com/AngularJS-Beers/"
},
"sldkjfslkjfslkjdskzzzlj": {
"desc": "Angular Conferences and Angular Camps in Barcelona, Spain.",
"rev": true,
"title": "Angular Camp",
"url": "http://angularcamp.org/"
} }
} }
}, },
@ -51,7 +62,7 @@
"logo": "", "logo": "",
"rev": true, "rev": true,
"title": "Adventures in Angular", "title": "Adventures in Angular",
"url": "https://devchat.tv/adv-in-angular/" "url": "https://devchat.tv/adventures-in-angular"
}, },
"sdlkfjsldfkj": { "sdlkfjsldfkj": {
"desc": "Weekly video podcast hosted by Jeff Whelpley with all the latest and greatest happenings in the wild world of Angular.", "desc": "Weekly video podcast hosted by Jeff Whelpley with all the latest and greatest happenings in the wild world of Angular.",
@ -66,6 +77,13 @@
"rev": true, "rev": true,
"title": "Happy Angular Podcast", "title": "Happy Angular Podcast",
"url": "https://happy-angular.de/" "url": "https://happy-angular.de/"
},
"sldkfjsldjf": {
"desc": "The live broadcast podcast all about JavaScript",
"logo": "",
"rev": true,
"title": "Javascript Air",
"url": "https://javascriptair.com/"
} }
} }
} }
@ -77,26 +95,40 @@
"Cross-Platform Development": { "Cross-Platform Development": {
"order": 5, "order": 5,
"resources": { "resources": {
"a2b": {
"desc": "Angular and React Native to build applications for Android and iOS",
"logo": "",
"rev": true,
"title": "ReactNative",
"url": "http://angular.github.io/react-native-renderer/"
},
"a3b": { "a3b": {
"desc": "Ionic offers a library of mobile-optimized HTML, CSS and JS components and tools for building highly interactive native and progressive web apps.", "desc": "Ionic offers a library of mobile-optimized HTML, CSS and JS components and tools for building highly interactive native and progressive web apps.",
"logo": "http://ionicframework.com/img/ionic-logo-white.svg", "logo": "http://ionicframework.com/img/ionic-logo-white.svg",
"rev": true, "rev": true,
"title": "Ionic", "title": "Ionic",
"url": "https://ionicframework.com/docs" "url": "http://ionicframework.com/docs/v2/"
}, },
"a4b": { "a4b": {
"desc": "Electron Platform for Angular.", "desc": "Electron Platform for Angular.",
"logo": "", "logo": "",
"rev": true, "rev": true,
"title": "Electron", "title": "Electron",
"url": "https://github.com/maximegris/angular-electron" "url": "http://github.com/angular/angular-electron"
}, },
"ab": { "ab": {
"desc": "NativeScript is how you build cross-platform, native iOS and Android apps with Angular and TypeScript. Get 100% access to native APIs via JavaScript and reuse of packages from NPM, CocoaPods and Gradle. Open source and backed by Telerik.", "desc": "NativeScript is how you build cross-platform, native iOS and Android apps with Angular and TypeScript. Get 100% access to native APIs via JavaScript and reuse of packages from NPM, CocoaPods and Gradle. Open source and backed by Telerik.",
"logo": "", "logo": "",
"rev": true, "rev": true,
"title": "NativeScript", "title": "NativeScript",
"url": "https://docs.nativescript.org/angular/start/introduction" "url": "https://github.com/NativeScript/nativescript-angular"
},
"ab5": {
"desc": "An Universal Windows App (uwp) powered by Angular",
"logo": "",
"rev": true,
"title": "Windows (UWP)",
"url": "http://github.com/preboot/angular2-universal-windows-app"
} }
} }
}, },
@ -107,13 +139,7 @@
"desc": "Reactive Extensions for Angular", "desc": "Reactive Extensions for Angular",
"rev": true, "rev": true,
"title": "ngrx", "title": "ngrx",
"url": "https://ngrx.io/" "url": "http://github.com/ngrx"
},
"ngxs": {
"desc": "NGXS is a state management pattern + library for Angular. NGXS is modeled after the CQRS pattern popularly implemented in libraries like Redux and NgRx but reduces boilerplate by using modern TypeScript features such as classes and decorators.",
"rev": true,
"title": "NGXS",
"url": "https://ngxs.io/"
}, },
"ab": { "ab": {
"desc": "The official library for Firebase and Angular", "desc": "The official library for Firebase and Angular",
@ -127,14 +153,21 @@
"logo": "http://www.angular-meteor.com/images/logo.png", "logo": "http://www.angular-meteor.com/images/logo.png",
"rev": true, "rev": true,
"title": "Meteor", "title": "Meteor",
"url": "https://github.com/urigo/angular-meteor" "url": "http://www.angular-meteor.com/angular2"
}, },
"ab3": { "ab3": {
"desc": "Apollo is a data stack for modern apps, built with GraphQL.", "desc": "Apollo is a data stack for modern apps, built with GraphQL.",
"logo": "http://docs.apollostack.com/logo/large.png", "logo": "http://docs.apollostack.com/logo/large.png",
"rev": true, "rev": true,
"title": "Apollo", "title": "Apollo",
"url": "https://www.apollographql.com/docs/angular/" "url": "http://docs.apollostack.com/apollo-client/angular2.html"
},
"ab4": {
"desc": "Angular Commerce is a solution for building modern e-commerce applications with power of Google Firebase. Set of components is design agnostic and allows to easily extend functionality.",
"logo": "",
"rev": true,
"title": "AngularCommerce",
"url": "https://github.com/NodeArt/angular-commerce"
}, },
"ngx-api-utils": { "ngx-api-utils": {
"desc": "ngx-api-utils is a lean library of utilities and helpers to quickly integrate any HTTP API (REST, Ajax, and any other) with Angular.", "desc": "ngx-api-utils is a lean library of utilities and helpers to quickly integrate any HTTP API (REST, Ajax, and any other) with Angular.",
@ -186,6 +219,12 @@
"Tooling": { "Tooling": {
"order": 2, "order": 2,
"resources": { "resources": {
"-KLIzHfBEr1qMMUDxfq3": {
"desc": "Generate an Angular CRUD application from an existing database schema",
"rev": true,
"title": "Celerio Angular Quickstart",
"url": "https://github.com/jaxio/celerio-angular-quickstart"
},
"a1": { "a1": {
"desc": "A Google Chrome Dev Tools extension for debugging Angular applications.", "desc": "A Google Chrome Dev Tools extension for debugging Angular applications.",
"logo": "https://augury.angular.io/images/augury-logo.svg", "logo": "https://augury.angular.io/images/augury-logo.svg",
@ -220,6 +259,13 @@
"title": "Codelyzer", "title": "Codelyzer",
"url": "https://github.com/mgechev/codelyzer" "url": "https://github.com/mgechev/codelyzer"
}, },
"e1": {
"desc": "This package provides facilities for developers building Angular applications on ASP.NET.",
"logo": "",
"rev": true,
"title": "Universal for ASP.NET",
"url": "https://github.com/aspnet/nodeservices"
},
"f1": { "f1": {
"desc": "This tool generates dedicated documentation for Angular applications.", "desc": "This tool generates dedicated documentation for Angular applications.",
"logo": "", "logo": "",
@ -227,6 +273,13 @@
"title": "Compodoc", "title": "Compodoc",
"url": "https://github.com/compodoc/compodoc" "url": "https://github.com/compodoc/compodoc"
}, },
"ncg": {
"desc": "Generate several types of CRUD apps complete with e2e testing using template-sets for Angular, Material Design, Bootstrap, Kendo UI, Ionic, ...",
"logo": "https://avatars3.githubusercontent.com/u/27976684",
"rev": true,
"title": "NinjaCodeGen - Angular CRUD Generator",
"url": "https://ninjaCodeGen.com"
},
"angular-playground": { "angular-playground": {
"desc": "UI development environment for building, testing, and documenting Angular applications.", "desc": "UI development environment for building, testing, and documenting Angular applications.",
"rev": true, "rev": true,
@ -277,6 +330,12 @@
"title": "Clarity Design System", "title": "Clarity Design System",
"url": "https://vmware.github.io/clarity/" "url": "https://vmware.github.io/clarity/"
}, },
"-KLIzI9BTvvP_hUwutXk": {
"desc": "UI components for Angular using Semantic UI",
"rev": true,
"title": "Semantic UI",
"url": "https://github.com/vladotesanovic/ngSemantic"
},
"-KMVB8P4TDfht8c0L1AE": { "-KMVB8P4TDfht8c0L1AE": {
"desc": "The Angular version of the Angular UI Bootstrap library. This library is being built from scratch in Typescript using the Bootstrap 4 CSS framework.", "desc": "The Angular version of the Angular UI Bootstrap library. This library is being built from scratch in Typescript using the Bootstrap 4 CSS framework.",
"rev": true, "rev": true,
@ -461,6 +520,12 @@
"Books": { "Books": {
"order": 1, "order": 1,
"resources": { "resources": {
"-KLI8vJ0ZkvWhqPembZ7": {
"desc": "A guide that helps developers get up to speed quickly on Angular and its accompanying technologies.",
"rev": true,
"title": "How to Get Started and Productive in Angular Fast",
"url": "http://www.amazon.com/How-Started-Productive-Angular-Fast-ebook/dp/B01D3B0ET4/ref=sr_1_1_twi_kin_2?ie=UTF8&qid=1462381159&sr=8-1"
},
"-KLIzGEp8Mh5W-FkiQnL": { "-KLIzGEp8Mh5W-FkiQnL": {
"desc": "Your quick, no-nonsense guide to building real-world apps with Angular", "desc": "Your quick, no-nonsense guide to building real-world apps with Angular",
"rev": true, "rev": true,
@ -471,7 +536,25 @@
"desc": "More than 15 books from O'Reilly about Angular", "desc": "More than 15 books from O'Reilly about Angular",
"rev": true, "rev": true,
"title": "O'Reilly Media", "title": "O'Reilly Media",
"url": "https://ssearch.oreilly.com/?q=angular" "url": "https://ssearch.oreilly.com/?q=angular+2&x=0&y=0"
},
"8ab": {
"desc": "This books shows all the steps necessary for the development of SPA (Single Page Application) applications with the brand new Angular",
"rev": true,
"title": "Practical Angular",
"url": "https://leanpub.com/practical-angular-2"
},
"a2b": {
"desc": "Publications and books from Manning about Angular",
"rev": true,
"title": "Manning Publications",
"url": "https://www.manning.com/search?q=angular"
},
"a4b": {
"desc": "From getting started with the Angular toolchain to writing applications with scalable front end architectures, this book walks you through everything you need to know.",
"rev": true,
"title": "Rangle's Angular Training Book",
"url": "http://ngcourse.rangle.io/"
}, },
"a5b": { "a5b": {
"desc": "The in-depth, complete, and up-to-date book on Angular. Become an Angular expert today.", "desc": "The in-depth, complete, and up-to-date book on Angular. Become an Angular expert today.",
@ -479,6 +562,12 @@
"title": "ng-book", "title": "ng-book",
"url": "https://www.ng-book.com/2/" "url": "https://www.ng-book.com/2/"
}, },
"a6b": {
"desc": "A Practical Introduction to the new Web Development Platform Angular",
"rev": true,
"title": "Angular Book",
"url": "https://leanpub.com/angular2-book"
},
"a7b": { "a7b": {
"desc": "This ebook will help you getting the philosophy of the framework: what comes from 1.x, what has been introduced and why", "desc": "This ebook will help you getting the philosophy of the framework: what comes from 1.x, what has been introduced and why",
"rev": true, "rev": true,
@ -489,13 +578,13 @@
"desc": "More than 10 books from Packt Publishing about Angular", "desc": "More than 10 books from Packt Publishing about Angular",
"rev": true, "rev": true,
"title": "Packt Publishing", "title": "Packt Publishing",
"url": "https://www.packtpub.com/catalogsearch/result/?q=angular" "url": "https://www.packtpub.com/all/?search=angular%202#"
}, },
"cnoring-rxjs-fundamentals": { "cnoring-rxjs-fundamentals": {
"desc": "A free book that covers all facets of working with Rxjs from your first Observable to how to make your code run at optimal speed with Schedulers.", "desc": "A free book that covers all facets of working with Rxjs from your first Observable to how to make your code run at optimal speed with Schedulers.",
"rev": true, "rev": true,
"title": "RxJS Ultimate", "title": "RxJS 5 Ultimate",
"url": "https://chrisnoring.gitbooks.io/rxjs-5-ultimate/content/" "url": "https://www.gitbook.com/book/chrisnoring/rxjs-5-ultimate/details"
}, },
"vsavkin-angular-router": { "vsavkin-angular-router": {
"desc": "This book is a comprehensive guide to the Angular router written by its designer. The book explores the library in depth, including the mental model, design constraints, subtleties of the API.", "desc": "This book is a comprehensive guide to the Angular router written by its designer. The book explores the library in depth, including the mental model, design constraints, subtleties of the API.",
@ -553,6 +642,18 @@
"title": "Academia Binaria (español)", "title": "Academia Binaria (español)",
"url": "http://academia-binaria.com/" "url": "http://academia-binaria.com/"
}, },
"-KLIzIOgdPXzI4LMOzYP": {
"desc": "In this course, you will learn the features listed above and so much more. This amazing Angular tutorial will cover the fundamentals of Angular (you dont even need to know Angular), TypeScript, and introduction to the programming concepts such as conditions, arrays, functions, directives, pipes, etc.",
"rev": true,
"title": "Eduonix Angular Fundamentals",
"url": "https://www.eduonix.com/courses/Web-Development/angular-2-fundamentals-for-web-developers"
},
"-KMUuOWwciL_S_o0fzFO": {
"desc": "The ngMigrate project is brought to you by Todd Motto, a Developer Advocate at Telerik, spreading the good word of Kendo UI, NativeScript and Angular & AngularJS. You can follow him on Twitter for questions, or even requests about this guide.",
"rev": true,
"title": "ngMigrate",
"url": "http://ngmigrate.telerik.com/"
},
"-KN3uNQvxifu26D6WKJW": { "-KN3uNQvxifu26D6WKJW": {
"category": "Education", "category": "Education",
"desc": "Create the future of web applications by taking Angular for a test drive.", "desc": "Create the future of web applications by taking Angular for a test drive.",
@ -573,14 +674,14 @@
"logo": "", "logo": "",
"rev": true, "rev": true,
"title": "Pluralsight", "title": "Pluralsight",
"url": "https://www.pluralsight.com/paths/angular" "url": "https://www.pluralsight.com/search?q=angular+2&categories=all"
}, },
"ab3": { "ab3": {
"desc": "Angular courses hosted by Udemy", "desc": "Angular courses hosted by Udemy",
"logo": "", "logo": "",
"rev": true, "rev": true,
"title": "Udemy", "title": "Udemy",
"url": "https://www.udemy.com/courses/search/?q=angular" "url": "https://www.udemy.com/courses/search/?ref=home&src=ukw&q=angular+2&lang=en"
}, },
"ab4": { "ab4": {
"desc": "Angular Fundamentals and advanced topics focused on Redux Style Angular Applications", "desc": "Angular Fundamentals and advanced topics focused on Redux Style Angular Applications",
@ -594,7 +695,13 @@
"logo": "", "logo": "",
"rev": true, "rev": true,
"title": "Frontend Masters", "title": "Frontend Masters",
"url": "https://frontendmasters.com/courses/angular-core/" "url": "https://frontendmasters.com/courses/angular-2/"
},
"ac6": {
"desc": "French language Angular course covering TypeScript, ES6, Dependency Injection, Observables, and more.",
"rev": true,
"title": "Wishtack's Angular Course (francais)",
"url": "http://courses.wishtack.com/angular-2/ecmascript-6"
}, },
"angular-love": { "angular-love": {
"desc": "Polish language Angular articles and information", "desc": "Polish language Angular articles and information",
@ -602,6 +709,12 @@
"title": "angular.love (Polski)", "title": "angular.love (Polski)",
"url": "http://www.angular.love/" "url": "http://www.angular.love/"
}, },
"angular2forms": {
"desc": "Learn about how to use Reactive Forms with Angular.",
"rev": true,
"title": "Angular Forms: Data Binding and Validation",
"url": "https://www.lynda.com/AngularJS-tutorials/Angular-2-Forms-Data-Binding-Validation/461451-2.html"
},
"learn-angular-fr": { "learn-angular-fr": {
"desc": "French language Angular content.", "desc": "French language Angular content.",
"rev": true, "rev": true,
@ -677,7 +790,7 @@
"desc": "Basic and Advanced training across Europe in German", "desc": "Basic and Advanced training across Europe in German",
"rev": true, "rev": true,
"title": "TheCodeCampus (German)", "title": "TheCodeCampus (German)",
"url": "https://www.thecodecampus.de/schulungen/angular" "url": "https://www.thecodecampus.de/#!/angularjs"
}, },
"-KLIzFhfGKi1xttqJ7Uh": { "-KLIzFhfGKi1xttqJ7Uh": {
"desc": "4 day in-depth Angular training in Israel", "desc": "4 day in-depth Angular training in Israel",
@ -710,6 +823,13 @@
"title": "Angular Boot Camp", "title": "Angular Boot Camp",
"url": "https://angularbootcamp.com" "url": "https://angularbootcamp.com"
}, },
"ab": {
"desc": "With Rangles Custom Training, you can cover Angular in comprehensive detail, on your premises or theirs. Learn directly from Angular experts who will tailor course material to suit your specific application needs.",
"logo": "",
"rev": true,
"title": "Rangle.io",
"url": "http://rangle.io/services/javascript-training/angular2-training/"
},
"ab3": { "ab3": {
"desc": "Trainings & Code Reviews. We help people to get a deep understanding of different technologies through trainings and code reviews. Our services can be arranged online, making it possible to join in from anywhere in the world, or on-site to get the best experience possible.", "desc": "Trainings & Code Reviews. We help people to get a deep understanding of different technologies through trainings and code reviews. Our services can be arranged online, making it possible to join in from anywhere in the world, or on-site to get the best experience possible.",
"logo": "", "logo": "",
@ -724,6 +844,12 @@
"title": "Learn Javascript (Russian)", "title": "Learn Javascript (Russian)",
"url": "https://learn.javascript.ru/courses/angular" "url": "https://learn.javascript.ru/courses/angular"
}, },
"sa200": {
"desc": "Free Angular training delivered by SFEIR in France",
"rev": true,
"title": "SFEIR School (French)",
"url": "https://school.sfeir.com/project/sa200/"
},
"zenika-angular": { "zenika-angular": {
"desc": "Angular trainings delivered by Zenika (FRANCE)", "desc": "Angular trainings delivered by Zenika (FRANCE)",
"rev": true, "rev": true,

View File

@ -208,16 +208,16 @@
"title": "Component Styles", "title": "Component Styles",
"tooltip": "Add CSS styles that are specific to a component." "tooltip": "Add CSS styles that are specific to a component."
}, },
{
"url": "guide/dynamic-component-loader",
"title": "Dynamic Components",
"tooltip": "Load components dynamically."
},
{ {
"url": "guide/elements", "url": "guide/elements",
"title": "Angular Elements", "title": "Angular Elements",
"tooltip": "Convert components to Custom Elements." "tooltip": "Convert components to Custom Elements."
}, },
{
"url": "guide/dynamic-component-loader",
"title": "Dynamic Components",
"tooltip": "Load components dynamically."
},
{ {
"url": "guide/attribute-directives", "url": "guide/attribute-directives",
"title": "Attribute Directives", "title": "Attribute Directives",
@ -456,11 +456,6 @@
"title": "Internationalization (i18n)", "title": "Internationalization (i18n)",
"tooltip": "Translate the app's template text into multiple languages." "tooltip": "Translate the app's template text into multiple languages."
}, },
{
"url": "guide/accessibility",
"title": "Accessibility",
"tooltip": "Design apps to be accessible to all users."
},
{ {
"title": "Service Workers & PWA", "title": "Service Workers & PWA",
"tooltip": "Angular service workers: Controlling caching of application resources.", "tooltip": "Angular service workers: Controlling caching of application resources.",

View File

@ -42,7 +42,7 @@ We've seeded this particular app with a top bar&mdash;containing the store name
<div class="callout is-helpful"> <div class="callout is-helpful">
<header>StackBlitz tips</header> <header>StackBlitz tips</header>
* Log into StackBlitz, so you can save and resume your work. If you have a GitHub account, you can log into StackBlitz with that account. In order to save your progress, first fork the project using the Fork button at the top left, then you'll be able to save your work to your own StackBlitz account by clicking the Save button. * Log into StackBlitz, so you can save and resume your work. If you have a GitHub account, you can log into StackBlitz with that account.
* To copy a code example from this tutorial, click the icon at the top right of the code example box, and then paste the code snippet from the clipboard into StackBlitz. * To copy a code example from this tutorial, click the icon at the top right of the code example box, and then paste the code snippet from the clipboard into StackBlitz.
* If the StackBlitz preview pane isn't showing what you expect, save and then click the refresh button. * If the StackBlitz preview pane isn't showing what you expect, save and then click the refresh button.
* StackBlitz is continually improving, so there may be slight differences in generated code, but the app's behavior will be the same. * StackBlitz is continually improving, so there may be slight differences in generated code, but the app's behavior will be the same.

View File

@ -13,11 +13,13 @@ Using the Angular CLI, generate a new component named `heroes`.
</code-example> </code-example>
The CLI creates a new folder, `src/app/heroes/`, and generates The CLI creates a new folder, `src/app/heroes/`, and generates
the three files of the `HeroesComponent` along with a test file. the four files of the `HeroesComponent`.
The `HeroesComponent` class file is as follows: The `HeroesComponent` class file is as follows:
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" region="v1" header="app/heroes/heroes.component.ts (initial version)" linenums="false"> <code-example
path="toh-pt1/src/app/heroes/heroes.component.ts" region="v1"
header="app/heroes/heroes.component.ts (initial version)" linenums="false">
</code-example> </code-example>
You always import the `Component` symbol from the Angular core library You always import the `Component` symbol from the Angular core library
@ -36,13 +38,13 @@ The CLI generated three metadata properties:
The [CSS element selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors), The [CSS element selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors),
`'app-heroes'`, matches the name of the HTML element that identifies this component within a parent component's template. `'app-heroes'`, matches the name of the HTML element that identifies this component within a parent component's template.
The `ngOnInit()` is a [lifecycle hook](guide/lifecycle-hooks#oninit). The `ngOnInit` is a [lifecycle hook](guide/lifecycle-hooks#oninit).
Angular calls `ngOnInit()` shortly after creating a component. Angular calls `ngOnInit` shortly after creating a component.
It's a good place to put initialization logic. It's a good place to put initialization logic.
Always `export` the component class so you can `import` it elsewhere ... like in the `AppModule`. Always `export` the component class so you can `import` it elsewhere ... like in the `AppModule`.
### Add a `hero` property ### Add a _hero_ property
Add a `hero` property to the `HeroesComponent` for a hero named "Windstorm." Add a `hero` property to the `HeroesComponent` for a hero named "Windstorm."
@ -58,7 +60,7 @@ replace it with a data binding to the new `hero` property.
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" header="heroes.component.html" region="show-hero-1" linenums="false"> <code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" header="heroes.component.html" region="show-hero-1" linenums="false">
</code-example> </code-example>
## Show the `HeroesComponent` view ## Show the _HeroesComponent_ view
To display the `HeroesComponent`, you must add it to the template of the shell `AppComponent`. To display the `HeroesComponent`, you must add it to the template of the shell `AppComponent`.
@ -100,7 +102,10 @@ The page no longer displays properly because you changed the hero from a string
Update the binding in the template to announce the hero's name Update the binding in the template to announce the hero's name
and show both `id` and `name` in a details layout like this: and show both `id` and `name` in a details layout like this:
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" region="show-hero-2" header="heroes.component.html (HeroesComponent's template)" linenums="false"> <code-example
path="toh-pt1/src/app/heroes/heroes.component.1.html"
region="show-hero-2"
header="heroes.component.html (HeroesComponent's template)" linenums="false">
</code-example> </code-example>
The browser refreshes and displays the hero's information. The browser refreshes and displays the hero's information.
@ -108,7 +113,9 @@ The browser refreshes and displays the hero's information.
## Format with the _UppercasePipe_ ## Format with the _UppercasePipe_
Modify the `hero.name` binding like this. Modify the `hero.name` binding like this.
<code-example path="toh-pt1/src/app/heroes/heroes.component.html" header="src/app/heroes/heroes.component.html" region="pipe"> <code-example
path="toh-pt1/src/app/heroes/heroes.component.html"
region="pipe">
</code-example> </code-example>
The browser refreshes and now the hero's name is displayed in capital letters. The browser refreshes and now the hero's name is displayed in capital letters.
@ -126,7 +133,7 @@ Users should be able to edit the hero name in an `<input>` textbox.
The textbox should both _display_ the hero's `name` property The textbox should both _display_ the hero's `name` property
and _update_ that property as the user types. and _update_ that property as the user types.
That means data flows from the component class _out to the screen_ and That means data flow from the component class _out to the screen_ and
from the screen _back to the class_. from the screen _back to the class_.
To automate that data flow, setup a two-way data binding between the `<input>` form element and the `hero.name` property. To automate that data flow, setup a two-way data binding between the `<input>` form element and the `hero.name` property.
@ -163,7 +170,7 @@ It belongs to the optional `FormsModule` and you must _opt-in_ to using it.
Angular needs to know how the pieces of your application fit together Angular needs to know how the pieces of your application fit together
and what other files and libraries the app requires. and what other files and libraries the app requires.
This information is called _metadata_. This information is called _metadata_
Some of the metadata is in the `@Component` decorators that you added to your component classes. Some of the metadata is in the `@Component` decorators that you added to your component classes.
Other critical metadata is in [`@NgModule`](guide/ngmodules) decorators. Other critical metadata is in [`@NgModule`](guide/ngmodules) decorators.
@ -189,7 +196,7 @@ region="ng-imports">
When the browser refreshes, the app should work again. You can edit the hero's name and see the changes reflected immediately in the `<h2>` above the textbox. When the browser refreshes, the app should work again. You can edit the hero's name and see the changes reflected immediately in the `<h2>` above the textbox.
### Declare `HeroesComponent` ### Declare _HeroesComponent_
Every component must be declared in _exactly one_ [NgModule](guide/ngmodules). Every component must be declared in _exactly one_ [NgModule](guide/ngmodules).
@ -199,11 +206,11 @@ So why did the application work?
It worked because the Angular CLI declared `HeroesComponent` in the `AppModule` when it generated that component. It worked because the Angular CLI declared `HeroesComponent` in the `AppModule` when it generated that component.
Open `src/app/app.module.ts` and find `HeroesComponent` imported near the top. Open `src/app/app.module.ts` and find `HeroesComponent` imported near the top.
<code-example path="toh-pt1/src/app/app.module.ts" header="src/app/app.module.ts" region="heroes-import" > <code-example path="toh-pt1/src/app/app.module.ts" region="heroes-import" >
</code-example> </code-example>
The `HeroesComponent` is declared in the `@NgModule.declarations` array. The `HeroesComponent` is declared in the `@NgModule.declarations` array.
<code-example path="toh-pt1/src/app/app.module.ts" header="src/app/app.module.ts" region="declarations"> <code-example path="toh-pt1/src/app/app.module.ts" region="declarations">
</code-example> </code-example>
Note that `AppModule` declares both application components, `AppComponent` and `HeroesComponent`. Note that `AppModule` declares both application components, `AppComponent` and `HeroesComponent`.

View File

@ -21,17 +21,19 @@ header="src/app/mock-heroes.ts">
## Displaying heroes ## Displaying heroes
You're about to display the list of heroes at the top of the `HeroesComponent`.
Open the `HeroesComponent` class file and import the mock `HEROES`. Open the `HeroesComponent` class file and import the mock `HEROES`.
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="import-heroes" header="src/app/heroes/heroes.component.ts (import HEROES)"> <code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="import-heroes" header="src/app/heroes/heroes.component.ts (import HEROES)">
</code-example> </code-example>
In the same file (`HeroesComponent` class), define a component property called `heroes` to expose the `HEROES` array for binding. In the same file (`HeroesComponent` class), define a component property called `heroes` to expose `HEROES` array for binding.
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts" region="component"> <code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="component">
</code-example> </code-example>
### List heroes with `*ngFor` ### List heroes with _*ngFor_
Open the `HeroesComponent` template file and make the following changes: Open the `HeroesComponent` template file and make the following changes:
@ -45,7 +47,7 @@ Make it look like this:
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="list" header="heroes.component.html (heroes template)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="list" header="heroes.component.html (heroes template)" linenums="false">
</code-example> </code-example>
That shows one hero. To list them all, add an `*ngFor` to the `<li>` to iterate through the list of heroes: Now change the `<li>` to this:
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="li"> <code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="li">
</code-example> </code-example>
@ -53,10 +55,10 @@ That shows one hero. To list them all, add an `*ngFor` to the `<li>` to iterate
The [`*ngFor`](guide/template-syntax#ngFor) is Angular's _repeater_ directive. The [`*ngFor`](guide/template-syntax#ngFor) is Angular's _repeater_ directive.
It repeats the host element for each element in a list. It repeats the host element for each element in a list.
The syntax in this example is as follows: In this example
* `<li>` is the host element. * `<li>` is the host element
* `heroes` holds the mock heroes list from the `HeroesComponent` class, the mock heroes list. * `heroes` is the list from the `HeroesComponent` class.
* `hero` holds the current hero object for each iteration through the list. * `hero` holds the current hero object for each iteration through the list.
<div class="alert is-important"> <div class="alert is-important">
@ -125,10 +127,9 @@ This is an example of Angular's [event binding](guide/template-syntax#event-bind
The parentheses around `click` tell Angular to listen for the `<li>` element's `click` event. The parentheses around `click` tell Angular to listen for the `<li>` element's `click` event.
When the user clicks in the `<li>`, Angular executes the `onSelect(hero)` expression. When the user clicks in the `<li>`, Angular executes the `onSelect(hero)` expression.
`onSelect()` is a `HeroesComponent` method that you're about to write.
In the next section, define an `onSelect()` method in `HeroesComponent` to Angular calls it with the `hero` object displayed in the clicked `<li>`,
display the hero that was defined in the `*ngFor` expression. the same `hero` defined previously in the `*ngFor` expression.
### Add the click event handler ### Add the click event handler
@ -141,11 +142,10 @@ to the component's `selectedHero`.
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="on-select" header="src/app/heroes/heroes.component.ts (onSelect)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="on-select" header="src/app/heroes/heroes.component.ts (onSelect)" linenums="false">
</code-example> </code-example>
### Add a details section ### Update the details template
Currently, you have a list in the component template. To click on a hero on the list The template still refers to the component's old `hero` property which no longer exists.
and reveal details about that hero, you need a section for the details to render in the Rename `hero` to `selectedHero`.
template. Add the following to `heroes.component.html` beneath the list section:
<code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="selectedHero-details" header="heroes.component.html (selected hero details)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="selectedHero-details" header="heroes.component.html (selected hero details)" linenums="false">
</code-example> </code-example>
@ -192,7 +192,7 @@ The heroes appear in a list and details about the clicked hero appear at the bot
#### Why it works #### Why it works
When `selectedHero` is undefined, the `ngIf` removes the hero detail from the DOM. There are no `selectedHero` bindings to consider. When `selectedHero` is undefined, the `ngIf` removes the hero detail from the DOM. There are no `selectedHero` bindings to worry about.
When the user picks a hero, `selectedHero` has a value and When the user picks a hero, `selectedHero` has a value and
`ngIf` puts the hero detail into the DOM. `ngIf` puts the hero detail into the DOM.

View File

@ -72,7 +72,7 @@ Amend the `@angular/core` import statement to include the `Input` symbol.
Add a `hero` property, preceded by the `@Input()` decorator. Add a `hero` property, preceded by the `@Input()` decorator.
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" header="src/app/hero-detail/hero-detail.component.ts" region="input-hero" linenums="false"> <code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" region="input-hero" linenums="false">
</code-example> </code-example>
That's the only change you should make to the `HeroDetailComponent` class. That's the only change you should make to the `HeroDetailComponent` class.

View File

@ -18,11 +18,11 @@ to inject it into the `HeroesComponent` constructor.
Services are a great way to share information among classes that _don't know each other_. Services are a great way to share information among classes that _don't know each other_.
You'll create a `MessageService` and inject it in two places: You'll create a `MessageService` and inject it in two places:
1. in `HeroService` which uses the service to send a message 1. in `HeroService` which uses the service to send a message.
2. in `MessagesComponent` which displays that message 2. in `MessagesComponent` which displays that message.
## Create the `HeroService` ## Create the _HeroService_
Using the Angular CLI, create a service called `hero`. Using the Angular CLI, create a service called `hero`.
@ -30,14 +30,14 @@ Using the Angular CLI, create a service called `hero`.
ng generate service hero ng generate service hero
</code-example> </code-example>
The command generates a skeleton `HeroService` class in `src/app/hero.service.ts` as follows: The command generates skeleton `HeroService` class in `src/app/hero.service.ts`
The `HeroService` class should look like the following example.
<code-example path="toh-pt4/src/app/hero.service.1.ts" region="new" <code-example path="toh-pt4/src/app/hero.service.1.ts" region="new"
header="src/app/hero.service.ts (new service)" linenums="false"> header="src/app/hero.service.ts (new service)" linenums="false">
</code-example> </code-example>
### _@Injectable()_ services
### `@Injectable()` services
Notice that the new service imports the Angular `Injectable` symbol and annotates Notice that the new service imports the Angular `Injectable` symbol and annotates
the class with the `@Injectable()` decorator. This marks the class as one that participates in the _dependency injection system_. The `HeroService` class is going to provide an injectable service, and it can also have its own injected dependencies. the class with the `@Injectable()` decorator. This marks the class as one that participates in the _dependency injection system_. The `HeroService` class is going to provide an injectable service, and it can also have its own injected dependencies.
@ -56,25 +56,27 @@ The implementation in _this_ tutorial will continue to deliver _mock heroes_.
Import the `Hero` and `HEROES`. Import the `Hero` and `HEROES`.
<code-example path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="import-heroes"> <code-example path="toh-pt4/src/app/hero.service.ts" region="import-heroes">
</code-example> </code-example>
Add a `getHeroes` method to return the _mock heroes_. Add a `getHeroes` method to return the _mock heroes_.
<code-example path="toh-pt4/src/app/hero.service.1.ts" header="src/app/hero.service.ts" region="getHeroes"> <code-example path="toh-pt4/src/app/hero.service.1.ts" region="getHeroes">
</code-example> </code-example>
{@a provide} {@a provide}
## Provide the `HeroService` ## Provide the `HeroService`
You must make the `HeroService` available to the dependency injection system You must make the `HeroService` available to the dependency injection system
before Angular can _inject_ it into the `HeroesComponent` by registering a _provider_. A provider is something that can create or deliver a service; in this case, it instantiates the `HeroService` class to provide the service. before Angular can _inject_ it into the `HeroesComponent`,
as you will do [below](#inject). You do this by registering a _provider_. A provider is something that can create or deliver a service; in this case, it instantiates the `HeroService` class to provide the service.
To make sure that the `HeroService` can provide this service, register it Now, you need to make sure that the `HeroService` is registered as the provider of this service.
with the _injector_, which is the object that is responsible for choosing You are registering it with an _injector_, which is the object that is responsible for choosing and injecting the provider where it is required.
and injecting the provider where the app requires it.
By default, the Angular CLI command `ng generate service` registers a provider with the _root injector_ for your service by including provider metadata, that is `providedIn: 'root'` in the `@Injectable()` decorator. By default, the Angular CLI command `ng generate service` registers a provider with the _root injector_ for your service by including provider metadata in the `@Injectable` decorator.
If you look at the `@Injectable()` statement right before the `HeroService` class definition, you can see that the `providedIn` metadata value is 'root':
``` ```
@Injectable({ @Injectable({
@ -113,7 +115,7 @@ Import the `HeroService` instead.
Replace the definition of the `heroes` property with a simple declaration. Replace the definition of the `heroes` property with a simple declaration.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts" region="heroes"> <code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="heroes">
</code-example> </code-example>
{@a inject} {@a inject}
@ -122,7 +124,7 @@ Replace the definition of the `heroes` property with a simple declaration.
Add a private `heroService` parameter of type `HeroService` to the constructor. Add a private `heroService` parameter of type `HeroService` to the constructor.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts" region="ctor"> <code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="ctor">
</code-example> </code-example>
The parameter simultaneously defines a private `heroService` property and identifies it as a `HeroService` injection site. The parameter simultaneously defines a private `heroService` property and identifies it as a `HeroService` injection site.
@ -130,16 +132,16 @@ The parameter simultaneously defines a private `heroService` property and identi
When Angular creates a `HeroesComponent`, the [Dependency Injection](guide/dependency-injection) system When Angular creates a `HeroesComponent`, the [Dependency Injection](guide/dependency-injection) system
sets the `heroService` parameter to the singleton instance of `HeroService`. sets the `heroService` parameter to the singleton instance of `HeroService`.
### Add `getHeroes()` ### Add _getHeroes()_
Create a function to retrieve the heroes from the service. Create a function to retrieve the heroes from the service.
<code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts" region="getHeroes"> <code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="getHeroes">
</code-example> </code-example>
{@a oninit} {@a oninit}
### Call it in `ngOnInit()` ### Call it in `ngOnInit`
While you could call `getHeroes()` in the constructor, that's not the best practice. While you could call `getHeroes()` in the constructor, that's not the best practice.
@ -148,9 +150,9 @@ The constructor shouldn't _do anything_.
It certainly shouldn't call a function that makes HTTP requests to a remote server as a _real_ data service would. It certainly shouldn't call a function that makes HTTP requests to a remote server as a _real_ data service would.
Instead, call `getHeroes()` inside the [*ngOnInit lifecycle hook*](guide/lifecycle-hooks) and Instead, call `getHeroes()` inside the [*ngOnInit lifecycle hook*](guide/lifecycle-hooks) and
let Angular call `ngOnInit()` at an appropriate time _after_ constructing a `HeroesComponent` instance. let Angular call `ngOnInit` at an appropriate time _after_ constructing a `HeroesComponent` instance.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts" region="ng-on-init"> <code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="ng-on-init">
</code-example> </code-example>
### See it run ### See it run
@ -165,7 +167,7 @@ which implies that the `HeroService` can fetch heroes synchronously.
The `HeroesComponent` consumes the `getHeroes()` result The `HeroesComponent` consumes the `getHeroes()` result
as if heroes could be fetched synchronously. as if heroes could be fetched synchronously.
<code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" header="src/app/heroes/heroes.component.ts" region="get-heroes"> <code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="get-heroes">
</code-example> </code-example>
This will not work in a real app. This will not work in a real app.
@ -179,11 +181,13 @@ and the browser will not block while the service waits.
`HeroService.getHeroes()` must have an _asynchronous signature_ of some kind. `HeroService.getHeroes()` must have an _asynchronous signature_ of some kind.
It can take a callback. It could return a `Promise`. It could return an `Observable`.
In this tutorial, `HeroService.getHeroes()` will return an `Observable` In this tutorial, `HeroService.getHeroes()` will return an `Observable`
because it will eventually use the Angular `HttpClient.get` method to fetch the heroes in part because it will eventually use the Angular `HttpClient.get` method to fetch the heroes
and [`HttpClient.get()` returns an `Observable`](guide/http). and [`HttpClient.get()` returns an `Observable`](guide/http).
### Observable `HeroService` ### Observable _HeroService_
`Observable` is one of the key classes in the [RxJS library](http://reactivex.io/rxjs/). `Observable` is one of the key classes in the [RxJS library](http://reactivex.io/rxjs/).
@ -192,12 +196,13 @@ In this tutorial, you'll simulate getting data from the server with the RxJS `of
Open the `HeroService` file and import the `Observable` and `of` symbols from RxJS. Open the `HeroService` file and import the `Observable` and `of` symbols from RxJS.
<code-example path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts (Observable imports)" region="import-observable"> <code-example path="toh-pt4/src/app/hero.service.ts"
header="src/app/hero.service.ts (Observable imports)" region="import-observable">
</code-example> </code-example>
Replace the `getHeroes()` method with the following: Replace the `getHeroes` method with this one.
<code-example path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="getHeroes-1"></code-example> <code-example path="toh-pt4/src/app/hero.service.ts" region="getHeroes-1"></code-example>
`of(HEROES)` returns an `Observable<Hero[]>` that emits _a single value_, the array of mock heroes. `of(HEROES)` returns an `Observable<Hero[]>` that emits _a single value_, the array of mock heroes.
@ -207,7 +212,7 @@ In the [HTTP tutorial](tutorial/toh-pt6), you'll call `HttpClient.get<Hero[]>()`
</div> </div>
### Subscribe in `HeroesComponent` ### Subscribe in _HeroesComponent_
The `HeroService.getHeroes` method used to return a `Hero[]`. The `HeroService.getHeroes` method used to return a `Hero[]`.
Now it returns an `Observable<Hero[]>`. Now it returns an `Observable<Hero[]>`.
@ -237,9 +242,9 @@ or the browser could freeze the UI while it waited for the server's response.
That _won't work_ when the `HeroService` is actually making requests of a remote server. That _won't work_ when the `HeroService` is actually making requests of a remote server.
The new version waits for the `Observable` to emit the array of heroes&mdash;which The new version waits for the `Observable` to emit the array of heroes&mdash;
could happen now or several minutes from now. which could happen now or several minutes from now.
The `subscribe()` method passes the emitted array to the callback, Then `subscribe` passes the emitted array to the callback,
which sets the component's `heroes` property. which sets the component's `heroes` property.
This asynchronous approach _will work_ when This asynchronous approach _will work_ when
@ -247,14 +252,14 @@ the `HeroService` requests heroes from the server.
## Show messages ## Show messages
This section guides you through the following: In this section you will
* adding a `MessagesComponent` that displays app messages at the bottom of the screen * add a `MessagesComponent` that displays app messages at the bottom of the screen.
* creating an injectable, app-wide `MessageService` for sending messages to be displayed * create an injectable, app-wide `MessageService` for sending messages to be displayed
* injecting `MessageService` into the `HeroService` * inject `MessageService` into the `HeroService`
* displaying a message when `HeroService` fetches heroes successfully * display a message when `HeroService` fetches heroes successfully.
### Create `MessagesComponent` ### Create _MessagesComponent_
Use the CLI to create the `MessagesComponent`. Use the CLI to create the `MessagesComponent`.
@ -264,16 +269,16 @@ Use the CLI to create the `MessagesComponent`.
The CLI creates the component files in the `src/app/messages` folder and declares the `MessagesComponent` in `AppModule`. The CLI creates the component files in the `src/app/messages` folder and declares the `MessagesComponent` in `AppModule`.
Modify the `AppComponent` template to display the generated `MessagesComponent`. Modify the `AppComponent` template to display the generated `MessagesComponent`
<code-example <code-example
header = "src/app/app.component.html" header = "/src/app/app.component.html"
path="toh-pt4/src/app/app.component.html"> path="toh-pt4/src/app/app.component.html">
</code-example> </code-example>
You should see the default paragraph from `MessagesComponent` at the bottom of the page. You should see the default paragraph from `MessagesComponent` at the bottom of the page.
### Create the `MessageService` ### Create the _MessageService_
Use the CLI to create the `MessageService` in `src/app`. Use the CLI to create the `MessageService` in `src/app`.
@ -283,7 +288,9 @@ Use the CLI to create the `MessageService` in `src/app`.
Open `MessageService` and replace its contents with the following. Open `MessageService` and replace its contents with the following.
<code-example header = "src/app/message.service.ts" path="toh-pt4/src/app/message.service.ts"> <code-example
header = "/src/app/message.service.ts"
path="toh-pt4/src/app/message.service.ts">
</code-example> </code-example>
The service exposes its cache of `messages` and two methods: one to `add()` a message to the cache and another to `clear()` the cache. The service exposes its cache of `messages` and two methods: one to `add()` a message to the cache and another to `clear()` the cache.
@ -291,10 +298,10 @@ The service exposes its cache of `messages` and two methods: one to `add()` a me
{@a inject-message-service} {@a inject-message-service}
### Inject it into the `HeroService` ### Inject it into the `HeroService`
In `HeroService`, import the `MessageService`. Re-open the `HeroService` and import the `MessageService`.
<code-example <code-example
header = "src/app/hero.service.ts (import MessageService)" header = "/src/app/hero.service.ts (import MessageService)"
path="toh-pt4/src/app/hero.service.ts" region="import-message-service"> path="toh-pt4/src/app/hero.service.ts" region="import-message-service">
</code-example> </code-example>
@ -303,7 +310,7 @@ Angular will inject the singleton `MessageService` into that property
when it creates the `HeroService`. when it creates the `HeroService`.
<code-example <code-example
path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="ctor"> path="toh-pt4/src/app/hero.service.ts" region="ctor">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -315,9 +322,9 @@ you inject the `MessageService` into the `HeroService` which is injected into th
### Send a message from `HeroService` ### Send a message from `HeroService`
Modify the `getHeroes()` method to send a message when the heroes are fetched. Modify the `getHeroes` method to send a message when the heroes are fetched.
<code-example path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="getHeroes"> <code-example path="toh-pt4/src/app/hero.service.ts" region="getHeroes">
</code-example> </code-example>
### Display the message from `HeroService` ### Display the message from `HeroService`
@ -327,17 +334,20 @@ including the message sent by the `HeroService` when it fetches heroes.
Open `MessagesComponent` and import the `MessageService`. Open `MessagesComponent` and import the `MessageService`.
<code-example header="src/app/messages/messages.component.ts (import MessageService)" path="toh-pt4/src/app/messages/messages.component.ts" region="import-message-service"> <code-example
header = "/src/app/messages/messages.component.ts (import MessageService)"
path="toh-pt4/src/app/messages/messages.component.ts" region="import-message-service">
</code-example> </code-example>
Modify the constructor with a parameter that declares a **public** `messageService` property. Modify the constructor with a parameter that declares a **public** `messageService` property.
Angular will inject the singleton `MessageService` into that property Angular will inject the singleton `MessageService` into that property
when it creates the `MessagesComponent`. when it creates the `MessagesComponent`.
<code-example path="toh-pt4/src/app/messages/messages.component.ts" header="src/app/messages/messages.component.ts" region="ctor"> <code-example
path="toh-pt4/src/app/messages/messages.component.ts" region="ctor">
</code-example> </code-example>
The `messageService` property **must be public** because you're going to bind to it in the template. The `messageService` property **must be public** because you're about to bind to it in the template.
<div class="alert is-important"> <div class="alert is-important">
@ -345,7 +355,7 @@ Angular only binds to _public_ component properties.
</div> </div>
### Bind to the `MessageService` ### Bind to the _MessageService_
Replace the CLI-generated `MessagesComponent` template with the following. Replace the CLI-generated `MessagesComponent` template with the following.

View File

@ -36,49 +36,59 @@ Use the CLI to generate it.
The generated file looks like this: The generated file looks like this:
<code-example path="toh-pt5/src/app/app-routing.module.0.ts" header="src/app/app-routing.module.ts (generated)"> <code-example path="toh-pt5/src/app/app-routing.module.0.ts"
header="src/app/app-routing.module.ts (generated)">
</code-example> </code-example>
Replace it with the following: You generally don't declare components in a routing module so you can delete the
`@NgModule.declarations` array and delete `CommonModule` references too.
<code-example path="toh-pt5/src/app/app-routing.module.1.ts" header="src/app/app-routing.module.ts (updated)"> You'll configure the router with `Routes` in the `RouterModule`
so import those two symbols from the `@angular/router` library.
Add an `@NgModule.exports` array with `RouterModule` in it.
Exporting `RouterModule` makes router directives available for use
in the `AppModule` components that will need them.
`AppRoutingModule` looks like this now:
<code-example path="toh-pt5/src/app/app-routing.module.ts"
region="v1"
header="src/app/app-routing.module.ts (v1)">
</code-example> </code-example>
First, `AppRoutingModule` imports `RouterModule` and `Routes` so the app can have routing functionality. The next import, `HeroesComponent`, will give the Router somewhere to go once you configure the routes. ### Add routes
Notice that the `CommonModule` references and `declarations` array are unecessary, so are no *Routes* tell the router which view to display when a user clicks a link or
longer part of `AppRoutingModule`. The following sections explain the rest of the `AppRoutingModule` in more detail.
### Routes
The next part of the file is where you configure your routes.
*Routes* tell the Router which view to display when a user clicks a link or
pastes a URL into the browser address bar. pastes a URL into the browser address bar.
Since `AppRoutingModule` already imports `HeroesComponent`, you can use it in the `routes` array:
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts"
region="heroes-route">
</code-example>
A typical Angular `Route` has two properties: A typical Angular `Route` has two properties:
* `path`: a string that matches the URL in the browser address bar. 1. `path`: a string that matches the URL in the browser address bar.
* `component`: the component that the router should create when navigating to this route. 1. `component`: the component that the router should create when navigating to this route.
This tells the router to match that URL to `path: 'heroes'` You intend to navigate to the `HeroesComponent` when the URL is something like `localhost:4200/heroes`.
and display the `HeroesComponent` when the URL is something like `localhost:4200/heroes`.
### `RouterModule.forRoot()` Import the `HeroesComponent` so you can reference it in a `Route`.
Then define an array of routes with a single `route` to that component.
The `@NgModule` metadata initializes the router and starts it listening for browser location changes. <code-example path="toh-pt5/src/app/app-routing.module.ts"
region="heroes-route">
</code-example>
The following line adds the `RouterModule` to the `AppRoutingModule` `imports` array and Once you've finished setting up, the router will match that URL to `path: 'heroes'`
configures it with the `routes` in one step by calling and display the `HeroesComponent`.
`RouterModule.forRoot()`:
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="ngmodule-imports"> ### _RouterModule.forRoot()_
You first must initialize the router and start it listening for browser location changes.
Add `RouterModule` to the `@NgModule.imports` array and
configure it with the `routes` in one step by calling
`RouterModule.forRoot()` _within_ the `imports` array, like this:
<code-example path="toh-pt5/src/app/app-routing.module.ts"
region="ngmodule-imports">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -89,21 +99,16 @@ configures it with the `routes` in one step by calling
</div> </div>
Next, `AppRoutingModule` exports `RouterModule` so it will be available throughout the app. ## Add _RouterOutlet_
Open the `AppComponent` template and replace the `<app-heroes>` element with a `<router-outlet>` element. Open the `AppComponent` template and replace the `<app-heroes>` element with a `<router-outlet>` element.
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts (exports array)" region="export-routermodule"> <code-example path="toh-pt5/src/app/app.component.html"
region="outlet"
header="src/app/app.component.html (router-outlet)">
</code-example> </code-example>
## Add `RouterOutlet` You removed `<app-heroes>` because you will only display the `HeroesComponent` when the user navigates to it.
Open the `AppComponent` template and replace the `<app-heroes>` element with a `<router-outlet>` element.
<code-example path="toh-pt5/src/app/app.component.html" region="outlet" header="src/app/app.component.html (router-outlet)">
</code-example>
The `AppComponent` template no longer needs `<app-heroes>` because the app will only display the `HeroesComponent` when the user navigates to it.
The `<router-outlet>` tells the router where to display routed views. The `<router-outlet>` tells the router where to display routed views.
@ -135,19 +140,22 @@ You should see the familiar heroes master/detail view.
## Add a navigation link (`routerLink`) ## Add a navigation link (`routerLink`)
Ideally, users should be able to click a link to navigate rather Users shouldn't have to paste a route URL into the address bar.
than pasting a route URL into the address bar. They should be able to click a link to navigate.
Add a `<nav>` element and, within that, an anchor element that, when clicked, Add a `<nav>` element and, within that, an anchor element that, when clicked,
triggers navigation to the `HeroesComponent`. triggers navigation to the `HeroesComponent`.
The revised `AppComponent` template looks like this: The revised `AppComponent` template looks like this:
<code-example path="toh-pt5/src/app/app.component.html" region="heroes" header="src/app/app.component.html (heroes RouterLink)"> <code-example
path="toh-pt5/src/app/app.component.html"
region="heroes"
header="src/app/app.component.html (heroes RouterLink)">
</code-example> </code-example>
A [`routerLink` attribute](#routerlink) is set to `"/heroes"`, A [`routerLink` attribute](#routerlink) is set to `"/heroes"`,
the string that the router matches to the route to `HeroesComponent`. the string that the router matches to the route to `HeroesComponent`.
The `routerLink` is the selector for the [`RouterLink` directive](/api/router/RouterLink) The `routerLink` is the selector for the [`RouterLink` directive](#routerlink)
that turns user clicks into router navigations. that turns user clicks into router navigations.
It's another of the public directives in the `RouterModule`. It's another of the public directives in the `RouterModule`.
@ -178,7 +186,7 @@ Add a `DashboardComponent` using the CLI:
The CLI generates the files for the `DashboardComponent` and declares it in `AppModule`. The CLI generates the files for the `DashboardComponent` and declares it in `AppModule`.
Replace the default file content in these three files as follows: Replace the default file content in these three files as follows and then return for a little discussion:
<code-tabs> <code-tabs>
<code-pane <code-pane
@ -203,11 +211,11 @@ The _template_ presents a grid of hero name links.
The _class_ is similar to the `HeroesComponent` class. The _class_ is similar to the `HeroesComponent` class.
* It defines a `heroes` array property. * It defines a `heroes` array property.
* The constructor expects Angular to inject the `HeroService` into a private `heroService` property. * The constructor expects Angular to inject the `HeroService` into a private `heroService` property.
* The `ngOnInit()` lifecycle hook calls `getHeroes()`. * The `ngOnInit()` lifecycle hook calls `getHeroes`.
This `getHeroes()` returns the sliced list of heroes at positions 1 and 5, returning only four of the Top Heroes (2nd, 3rd, 4th, and 5th). This `getHeroes` returns the sliced list of heroes at positions 1 and 5, returning only four of the Top Heroes (2nd, 3rd, 4th, and 5th).
<code-example path="toh-pt5/src/app/dashboard/dashboard.component.ts" header="src/app/dashboard/dashboard.component.ts" region="getHeroes"> <code-example path="toh-pt5/src/app/dashboard/dashboard.component.ts" region="getHeroes">
</code-example> </code-example>
### Add the dashboard route ### Add the dashboard route
@ -216,24 +224,29 @@ To navigate to the dashboard, the router needs an appropriate route.
Import the `DashboardComponent` in the `AppRoutingModule`. Import the `DashboardComponent` in the `AppRoutingModule`.
<code-example path="toh-pt5/src/app/app-routing.module.ts" region="import-dashboard" header="src/app/app-routing.module.ts (import DashboardComponent)"> <code-example
path="toh-pt5/src/app/app-routing.module.ts"
region="import-dashboard"
header="src/app/app-routing.module.ts (import DashboardComponent)">
</code-example> </code-example>
Add a route to the `AppRoutingModule.routes` array that matches a path to the `DashboardComponent`. Add a route to the `AppRoutingModule.routes` array that matches a path to the `DashboardComponent`.
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="dashboard-route"> <code-example
path="toh-pt5/src/app/app-routing.module.ts"
region="dashboard-route">
</code-example> </code-example>
### Add a default route ### Add a default route
When the app starts, the browser's address bar points to the web site's root. When the app starts, the browsers address bar points to the web site's root.
That doesn't match any existing route so the router doesn't navigate anywhere. That doesn't match any existing route so the router doesn't navigate anywhere.
The space below the `<router-outlet>` is blank. The space below the `<router-outlet>` is blank.
To make the app navigate to the dashboard automatically, add the following To make the app navigate to the dashboard automatically, add the following
route to the `AppRoutingModule.Routes` array. route to the `AppRoutingModule.Routes` array.
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="redirect-route"> <code-example path="toh-pt5/src/app/app-routing.module.ts" region="redirect-route">
</code-example> </code-example>
This route redirects a URL that fully matches the empty path to the route whose path is `'/dashboard'`. This route redirects a URL that fully matches the empty path to the route whose path is `'/dashboard'`.
@ -288,19 +301,27 @@ A URL like `~/detail/11` would be a good URL for navigating to the *Hero Detail*
Open `AppRoutingModule` and import `HeroDetailComponent`. Open `AppRoutingModule` and import `HeroDetailComponent`.
<code-example path="toh-pt5/src/app/app-routing.module.ts" region="import-herodetail" header="src/app/app-routing.module.ts (import HeroDetailComponent)"> <code-example
path="toh-pt5/src/app/app-routing.module.ts"
region="import-herodetail"
header="src/app/app-routing.module.ts (import HeroDetailComponent)">
</code-example> </code-example>
Then add a _parameterized_ route to the `AppRoutingModule.routes` array that matches the path pattern to the _hero detail_ view. Then add a _parameterized_ route to the `AppRoutingModule.routes` array that matches the path pattern to the _hero detail_ view.
<code-example path="toh-pt5/src/app/app-routing.module.ts" header="src/app/app-routing.module.ts" region="detail-route"> <code-example
path="toh-pt5/src/app/app-routing.module.ts"
region="detail-route">
</code-example> </code-example>
The colon (:) in the `path` indicates that `:id` is a placeholder for a specific hero `id`. The colon (:) in the `path` indicates that `:id` is a placeholder for a specific hero `id`.
At this point, all application routes are in place. At this point, all application routes are in place.
<code-example path="toh-pt5/src/app/app-routing.module.ts" region="routes" header="src/app/app-routing.module.ts (all routes)"> <code-example
path="toh-pt5/src/app/app-routing.module.ts"
region="routes"
header="src/app/app-routing.module.ts (all routes)">
</code-example> </code-example>
### `DashboardComponent` hero links ### `DashboardComponent` hero links
@ -326,7 +347,10 @@ to insert the current iteration's `hero.id` into each
The hero items in the `HeroesComponent` are `<li>` elements whose click events The hero items in the `HeroesComponent` are `<li>` elements whose click events
are bound to the component's `onSelect()` method. are bound to the component's `onSelect()` method.
<code-example path="toh-pt4/src/app/heroes/heroes.component.html" region="list" header="src/app/heroes/heroes.component.html (list with onSelect)"> <code-example
path="toh-pt4/src/app/heroes/heroes.component.html"
region="list"
header="src/app/heroes/heroes.component.html (list with onSelect)">
</code-example> </code-example>
Strip the `<li>` back to just its `*ngFor`, Strip the `<li>` back to just its `*ngFor`,
@ -334,7 +358,10 @@ wrap the badge and name in an anchor element (`<a>`),
and add a `routerLink` attribute to the anchor that and add a `routerLink` attribute to the anchor that
is the same as in the dashboard template is the same as in the dashboard template
<code-example path="toh-pt5/src/app/heroes/heroes.component.html" region="list" header="src/app/heroes/heroes.component.html (list with links)"> <code-example
path="toh-pt5/src/app/heroes/heroes.component.html"
region="list"
header="src/app/heroes/heroes.component.html (list with links)">
</code-example> </code-example>
You'll have to fix the private stylesheet (`heroes.component.css`) to make You'll have to fix the private stylesheet (`heroes.component.css`) to make
@ -349,10 +376,13 @@ the `onSelect()` method and `selectedHero` property are no longer used.
It's nice to tidy up and you'll be grateful to yourself later. It's nice to tidy up and you'll be grateful to yourself later.
Here's the class after pruning away the dead code. Here's the class after pruning away the dead code.
<code-example path="toh-pt5/src/app/heroes/heroes.component.ts" region="class" header="src/app/heroes/heroes.component.ts (cleaned up)" linenums="false"> <code-example
path="toh-pt5/src/app/heroes/heroes.component.ts"
region="class"
header="src/app/heroes/heroes.component.ts (cleaned up)" linenums="false">
</code-example> </code-example>
## Routable `HeroDetailComponent` ## Routable *HeroDetailComponent*
Previously, the parent `HeroesComponent` set the `HeroDetailComponent.hero` Previously, the parent `HeroesComponent` set the `HeroDetailComponent.hero`
property and the `HeroDetailComponent` displayed the hero. property and the `HeroDetailComponent` displayed the hero.
@ -360,16 +390,18 @@ property and the `HeroDetailComponent` displayed the hero.
`HeroesComponent` doesn't do that anymore. `HeroesComponent` doesn't do that anymore.
Now the router creates the `HeroDetailComponent` in response to a URL such as `~/detail/11`. Now the router creates the `HeroDetailComponent` in response to a URL such as `~/detail/11`.
The `HeroDetailComponent` needs a new way to obtain the hero-to-display. The `HeroDetailComponent` needs a new way to obtain the _hero-to-display_.
This section explains the following:
* Get the route that created it * Get the route that created it,
* Extract the `id` from the route * Extract the `id` from the route
* Acquire the hero with that `id` from the server via the `HeroService` * Acquire the hero with that `id` from the server via the `HeroService`
Add the following imports: Add the following imports:
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="added-imports" header="src/app/hero-detail/hero-detail.component.ts"> <code-example
path="toh-pt5/src/app/hero-detail/hero-detail.component.ts"
region="added-imports"
header="src/app/hero-detail/hero-detail.component.ts">
</code-example> </code-example>
{@a hero-detail-ctor} {@a hero-detail-ctor}
@ -377,25 +409,27 @@ Add the following imports:
Inject the `ActivatedRoute`, `HeroService`, and `Location` services Inject the `ActivatedRoute`, `HeroService`, and `Location` services
into the constructor, saving their values in private fields: into the constructor, saving their values in private fields:
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" header="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="ctor"> <code-example
path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="ctor">
</code-example> </code-example>
The [`ActivatedRoute`](api/router/ActivatedRoute) holds information about the route to this instance of the `HeroDetailComponent`. The [`ActivatedRoute`](api/router/ActivatedRoute) holds information about the route to this instance of the `HeroDetailComponent`.
This component is interested in the route's parameters extracted from the URL. This component is interested in the route's bag of parameters extracted from the URL.
The "id" parameter is the `id` of the hero to display. The _"id"_ parameter is the `id` of the hero to display.
The [`HeroService`](tutorial/toh-pt4) gets hero data from the remote server The [`HeroService`](tutorial/toh-pt4) gets hero data from the remote server
and this component will use it to get the hero-to-display. and this component will use it to get the _hero-to-display_.
The [`location`](api/common/Location) is an Angular service for interacting with the browser. The [`location`](api/common/Location) is an Angular service for interacting with the browser.
You'll use it [later](#goback) to navigate back to the view that navigated here. You'll use it [later](#goback) to navigate back to the view that navigated here.
### Extract the `id` route parameter ### Extract the _id_ route parameter
In the `ngOnInit()` [lifecycle hook](guide/lifecycle-hooks#oninit) In the `ngOnInit()` [lifecycle hook](guide/lifecycle-hooks#oninit)
call `getHero()` and define it as follows. call `getHero()` and define it as follows.
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" header="src/app/hero-detail/hero-detail.component.ts" region="ngOnInit"> <code-example
path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="ngOnInit">
</code-example> </code-example>
The `route.snapshot` is a static image of the route information shortly after the component was created. The `route.snapshot` is a static image of the route information shortly after the component was created.
@ -413,14 +447,18 @@ Add it now.
### Add `HeroService.getHero()` ### Add `HeroService.getHero()`
Open `HeroService` and add the following `getHero()` method with the `id` after the `getHeroes()` method: Open `HeroService` and add this `getHero()` method
<code-example path="toh-pt5/src/app/hero.service.ts" region="getHero" header="src/app/hero.service.ts (getHero)"> <code-example
path="toh-pt5/src/app/hero.service.ts"
region="getHero"
header="src/app/hero.service.ts (getHero)">
</code-example> </code-example>
<div class="alert is-important"> <div class="alert is-important">
Note the backticks ( &#96; ) that define a JavaScript Note the backticks ( &#96; ) that
define a JavaScript
[_template literal_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) for embedding the `id`. [_template literal_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) for embedding the `id`.
</div> </div>
@ -452,7 +490,10 @@ It would be nice to have a button on the `HeroDetail` view that can do that.
Add a *go back* button to the bottom of the component template and bind it Add a *go back* button to the bottom of the component template and bind it
to the component's `goBack()` method. to the component's `goBack()` method.
<code-example path="toh-pt5/src/app/hero-detail/hero-detail.component.html" region="back-button" header="src/app/hero-detail/hero-detail.component.html (back button)"> <code-example
path="toh-pt5/src/app/hero-detail/hero-detail.component.html"
region="back-button"
header="src/app/hero-detail/hero-detail.component.html (back button)">
</code-example> </code-example>
Add a `goBack()` _method_ to the component class that navigates backward one step Add a `goBack()` _method_ to the component class that navigates backward one step
@ -468,13 +509,15 @@ Refresh the browser and start clicking.
Users can navigate around the app, from the dashboard to hero details and back, Users can navigate around the app, from the dashboard to hero details and back,
from heroes list to the mini detail to the hero details and back to the heroes again. from heroes list to the mini detail to the hero details and back to the heroes again.
You've met all of the navigational requirements that propelled this page.
## Final code review ## Final code review
Here are the code files discussed on this page and your app should look like this <live-example></live-example>. Here are the code files discussed on this page and your app should look like this <live-example></live-example>.
{@a approutingmodule} {@a approutingmodule}
{@a appmodule} {@a appmodule}
#### `AppRoutingModule`, `AppModule`, and `HeroService` #### _AppRoutingModule_, _AppModule_, and _HeroService_
<code-tabs> <code-tabs>
<code-pane <code-pane
@ -492,7 +535,7 @@ Here are the code files discussed on this page and your app should look like thi
</code-tabs> </code-tabs>
{@a appcomponent} {@a appcomponent}
#### `AppComponent` #### _AppComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
@ -507,7 +550,7 @@ Here are the code files discussed on this page and your app should look like thi
</code-tabs> </code-tabs>
{@a dashboardcomponent} {@a dashboardcomponent}
#### `DashboardComponent` #### _DashboardComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
@ -524,7 +567,7 @@ Here are the code files discussed on this page and your app should look like thi
</code-tabs> </code-tabs>
{@a heroescomponent} {@a heroescomponent}
#### `HeroesComponent` #### _HeroesComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
@ -543,7 +586,7 @@ Here are the code files discussed on this page and your app should look like thi
</code-tabs> </code-tabs>
{@a herodetailcomponent} {@a herodetailcomponent}
#### `HeroDetailComponent` #### _HeroDetailComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane

View File

@ -13,119 +13,146 @@ When you're done with this page, the app should look like this <live-example></l
`HttpClient` is Angular's mechanism for communicating with a remote server over HTTP. `HttpClient` is Angular's mechanism for communicating with a remote server over HTTP.
Make `HttpClient` available everywhere in the app in two steps. First, add it to the root `AppModule` by importing it: To make `HttpClient` available everywhere in the app:
<code-example path="toh-pt6/src/app/app.module.ts" region="import-http-client" header="src/app/app.module.ts (HttpClientModule import)"> * open the root `AppModule`
</code-example> * import the `HttpClientModule` symbol from `@angular/common/http`
Next, still in the `AppModule`, add `HttpClient` to the `imports` array: <code-example
path="toh-pt6/src/app/app.module.ts"
<code-example path="toh-pt6/src/app/app.module.ts" region="import-httpclientmodule" header="src/app/app.module.ts (imports array excerpt)"> region="import-http-client"
header="src/app/app.module.ts (Http Client import)">
</code-example> </code-example>
* add it to the `@NgModule.imports` array
## Simulate a data server ## Simulate a data server
This tutorial sample mimics communication with a remote data server by using the This tutorial sample _mimics_ communication with a remote data server by using the
[In-memory Web API](https://github.com/angular/in-memory-web-api "In-memory Web API") module. [_In-memory Web API_](https://github.com/angular/in-memory-web-api "In-memory Web API") module.
After installing the module, the app will make requests to and receive responses from the `HttpClient` After installing the module, the app will make requests to and receive responses from the `HttpClient`
without knowing that the *In-memory Web API* is intercepting those requests, without knowing that the *In-memory Web API* is intercepting those requests,
applying them to an in-memory data store, and returning simulated responses. applying them to an in-memory data store, and returning simulated responses.
By using the In-memory Web API, you won't have to set up a server to learn about `HttpClient`. This facility is a great convenience for the tutorial.
You won't have to set up a server to learn about `HttpClient`.
It may also be convenient in the early stages of your own app development when
the server's web api is ill-defined or not yet implemented.
<div class="alert is-important"> <div class="alert is-important">
**Important:** the In-memory Web API module has nothing to do with HTTP in Angular. **Important:** the *In-memory Web API* module has nothing to do with HTTP in Angular.
If you're just reading this tutorial to learn about `HttpClient`, you can [skip over](#import-heroes) this step. If you're just _reading_ this tutorial to learn about `HttpClient`, you can [skip over](#import-heroes) this step.
If you're coding along with this tutorial, stay here and add the In-memory Web API now. If you're _coding along_ with this tutorial, stay here and add the *In-memory Web API* now.
</div> </div>
Install the In-memory Web API package from npm with the following command: Install the *In-memory Web API* package from _npm_
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
npm install angular-in-memory-web-api --save npm install angular-in-memory-web-api --save
</code-example> </code-example>
In the `AppModule`, import the `HttpClientInMemoryWebApiModule` and the `InMemoryDataService` class,
which you will create in a moment.
<code-example path="toh-pt6/src/app/app.module.ts" region="import-in-mem-stuff" header="src/app/app.module.ts (In-memory Web API imports)"> The class `src/app/in-memory-data.service.ts` is generated by the following command:
</code-example>
After the `HttpClientModule`, add the `HttpClientInMemoryWebApiModule`
to the `AppModule` `imports` array and configure it with the `InMemoryDataService`.
<code-example path="toh-pt6/src/app/app.module.ts" header="src/app/app.module.ts (imports array excerpt)" region="in-mem-web-api-imports">
</code-example>
The `forRoot()` configuration method takes an `InMemoryDataService` class
that primes the in-memory database.
Generate the class `src/app/in-memory-data.service.ts` with the following command:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate service InMemoryData ng generate service InMemoryData
</code-example> </code-example>
Replace the default contents of `in-memory-data.service.ts` with the following: This class has the following content:
<code-example path="toh-pt6/src/app/in-memory-data.service.ts" region="init" header="src/app/in-memory-data.service.ts" linenums="false"></code-example> <code-example path="toh-pt6/src/app/in-memory-data.service.ts" region="init" header="src/app/in-memory-data.service.ts" linenums="false"></code-example>
The `in-memory-data.service.ts` file replaces `mock-heroes.ts`, which is now safe to delete. This file replaces `mock-heroes.ts`, which is now safe to delete.
When the server is ready, you'll detach the In-memory Web API, and the app's requests will go through to the server. When your server is ready, detach the *In-memory Web API*, and the app's requests will go through to the server.
Now back to the `HttpClient` story.
Import the `HttpClientInMemoryWebApiModule` and the `InMemoryDataService` class.
<code-example
path="toh-pt6/src/app/app.module.ts"
region="import-in-mem-stuff"
header="src/app/app.module.ts (In-memory Web API imports)">
</code-example>
Add the `HttpClientInMemoryWebApiModule` to the `@NgModule.imports` array&mdash;
_after importing the `HttpClientModule`_,
&mdash;while configuring it with the `InMemoryDataService`.
<code-example
path="toh-pt6/src/app/app.module.ts"
region="in-mem-web-api-imports">
</code-example>
The `forRoot()` configuration method takes an `InMemoryDataService` class
that primes the in-memory database.
{@a import-heroes} {@a import-heroes}
## Heroes and HTTP ## Heroes and HTTP
In the `HeroService`, import `HttpClient` and `HttpHeaders`: Import some HTTP symbols that you'll need:
<code-example path="toh-pt6/src/app/hero.service.ts" region="import-httpclient" header="src/app/hero.service.ts (import HTTP symbols)"> <code-example
path="toh-pt6/src/app/hero.service.ts"
region="import-httpclient"
header="src/app/hero.service.ts (import HTTP symbols)">
</code-example> </code-example>
Still in the `HeroService`, inject `HttpClient` into the constructor in a private property called `http`. Inject `HttpClient` into the constructor in a private property called `http`.
<code-example path="toh-pt6/src/app/hero.service.ts" header="src/app/hero.service.ts" region="ctor" > <code-example
path="toh-pt6/src/app/hero.service.ts"
region="ctor" >
</code-example> </code-example>
Notice that you keep injecting the `MessageService` but since you'll call it so frequently, wrap it in a private `log()` method: Keep injecting the `MessageService`. You'll call it so frequently that
you'll wrap it in a private `log()` method.
<code-example path="toh-pt6/src/app/hero.service.ts" header="src/app/hero.service.ts" region="log" > <code-example
path="toh-pt6/src/app/hero.service.ts"
region="log" >
</code-example> </code-example>
Define the `heroesUrl` of the form `:base/:collectionName` with the address of the heroes resource on the server. Define the `heroesUrl` of the form `:base/:collectionName` with the address of the heroes resource on the server.
Here `base` is the resource to which requests are made, Here `base` is the resource to which requests are made,
and `collectionName` is the heroes data object in the `in-memory-data-service.ts`. and `collectionName` is the heroes data object in the `in-memory-data-service.ts`.
<code-example path="toh-pt6/src/app/hero.service.ts" header="src/app/hero.service.ts" region="heroesUrl" > <code-example
path="toh-pt6/src/app/hero.service.ts"
region="heroesUrl" >
</code-example> </code-example>
### Get heroes with `HttpClient` ### Get heroes with _HttpClient_
The current `HeroService.getHeroes()` The current `HeroService.getHeroes()`
uses the RxJS `of()` function to return an array of mock heroes uses the RxJS `of()` function to return an array of mock heroes
as an `Observable<Hero[]>`. as an `Observable<Hero[]>`.
<code-example path="toh-pt4/src/app/hero.service.ts" region="getHeroes-1" header="src/app/hero.service.ts (getHeroes with RxJs 'of()')"> <code-example
path="toh-pt4/src/app/hero.service.ts"
region="getHeroes-1"
header="src/app/hero.service.ts (getHeroes with RxJs 'of()')">
</code-example> </code-example>
Convert that method to use `HttpClient` as follows: Convert that method to use `HttpClient`
<code-example
<code-example path="toh-pt6/src/app/hero.service.ts" header="src/app/hero.service.ts" region="getHeroes-1"> path="toh-pt6/src/app/hero.service.ts"
region="getHeroes-1">
</code-example> </code-example>
Refresh the browser. The hero data should successfully load from the Refresh the browser. The hero data should successfully load from the
mock server. mock server.
You've swapped `of()` for `http.get()` and the app keeps working without any other changes You've swapped `of` for `http.get` and the app keeps working without any other changes
because both functions return an `Observable<Hero[]>`. because both functions return an `Observable<Hero[]>`.
### `HttpClient` methods return one value ### Http methods return one value
All `HttpClient` methods return an RxJS `Observable` of something. All `HttpClient` methods return an RxJS `Observable` of something.
@ -135,23 +162,23 @@ You make a request, it returns a single response.
In general, an observable _can_ return multiple values over time. In general, an observable _can_ return multiple values over time.
An observable from `HttpClient` always emits a single value and then completes, never to emit again. An observable from `HttpClient` always emits a single value and then completes, never to emit again.
This particular `HttpClient.get()` call returns an `Observable<Hero[]>`; that is, "_an observable of hero arrays_". In practice, it will only return a single hero array. This particular `HttpClient.get` call returns an `Observable<Hero[]>`, literally "_an observable of hero arrays_". In practice, it will only return a single hero array.
### `HttpClient.get()` returns response data ### _HttpClient.get_ returns response data
`HttpClient.get()` returns the body of the response as an untyped JSON object by default. `HttpClient.get` returns the _body_ of the response as an untyped JSON object by default.
Applying the optional type specifier, `<Hero[]>` , gives you a typed result object. Applying the optional type specifier, `<Hero[]>` , gives you a typed result object.
The server's data API determines the shape of the JSON data. The shape of the JSON data is determined by the server's data API.
The _Tour of Heroes_ data API returns the hero data as an array. The _Tour of Heroes_ data API returns the hero data as an array.
<div class="alert is-helpful"> <div class="alert is-helpful">
Other APIs may bury the data that you want within an object. Other APIs may bury the data that you want within an object.
You might have to dig that data out by processing the `Observable` result You might have to dig that data out by processing the `Observable` result
with the RxJS `map()` operator. with the RxJS `map` operator.
Although not discussed here, there's an example of `map()` in the `getHeroNo404()` Although not discussed here, there's an example of `map` in the `getHeroNo404()`
method included in the sample source code. method included in the sample source code.
</div> </div>
@ -165,51 +192,59 @@ To catch errors, you **"pipe" the observable** result from `http.get()` through
Import the `catchError` symbol from `rxjs/operators`, along with some other operators you'll need later. Import the `catchError` symbol from `rxjs/operators`, along with some other operators you'll need later.
<code-example path="toh-pt6/src/app/hero.service.ts" header="src/app/hero.service.ts" region="import-rxjs-operators"> <code-example
path="toh-pt6/src/app/hero.service.ts"
region="import-rxjs-operators">
</code-example> </code-example>
Now extend the observable result with the `pipe()` method and Now extend the observable result with the `.pipe()` method and
give it a `catchError()` operator. give it a `catchError()` operator.
<code-example path="toh-pt6/src/app/hero.service.ts" region="getHeroes-2" header="src/app/hero.service.ts"> <code-example
path="toh-pt6/src/app/hero.service.ts"
region="getHeroes-2" >
</code-example> </code-example>
The `catchError()` operator intercepts an **`Observable` that failed**. The `catchError()` operator intercepts an **`Observable` that failed**.
It passes the error an error handler that can do what it wants with the error. It passes the error an _error handler_ that can do what it wants with the error.
The following `handleError()` method reports the error and then returns an The following `handleError()` method reports the error and then returns an
innocuous result so that the application keeps working. innocuous result so that the application keeps working.
#### `handleError` #### _handleError_
The following `handleError()` will be shared by many `HeroService` methods The following `handleError()` will be shared by many `HeroService` methods
so it's generalized to meet their different needs. so it's generalized to meet their different needs.
Instead of handling the error directly, it returns an error handler function to `catchError` that it Instead of handling the error directly, it returns an _error handler_ function to `catchError` that it
has configured with both the name of the operation that failed and a safe return value. has configured with both the name of the operation that failed and a safe return value.
<code-example path="toh-pt6/src/app/hero.service.ts" header="src/app/hero.service.ts" region="handleError"> <code-example
path="toh-pt6/src/app/hero.service.ts"
region="handleError">
</code-example> </code-example>
After reporting the error to the console, the handler constructs After reporting the error to console, the handler constructs
a user friendly message and returns a safe value to the app so the app can keep working. a user friendly message and returns a safe value to the app so it can keep working.
Because each service method returns a different kind of `Observable` result, Because each service method returns a different kind of `Observable` result,
`handleError()` takes a type parameter so it can return the safe value as the type that the app expects. `handleError()` takes a type parameter so it can return the safe value as the type that the app expects.
### Tap into the Observable ### Tap into the _Observable_
The `HeroService` methods will **tap** into the flow of observable values The `HeroService` methods will **tap** into the flow of observable values
and send a message, via the `log()` method, to the message area at the bottom of the page. and send a message (via `log()`) to the message area at the bottom of the page.
They'll do that with the RxJS `tap()` operator, They'll do that with the RxJS `tap` operator,
which looks at the observable values, does something with those values, which _looks_ at the observable values, does _something_ with those values,
and passes them along. and passes them along.
The `tap()` call back doesn't touch the values themselves. The `tap` call back doesn't touch the values themselves.
Here is the final version of `getHeroes()` with the `tap()` that logs the operation. Here is the final version of `getHeroes` with the `tap` that logs the operation.
<code-example path="toh-pt6/src/app/hero.service.ts" header="src/app/hero.service.ts" region="getHeroes" > <code-example
path="toh-pt6/src/app/hero.service.ts"
region="getHeroes" >
</code-example> </code-example>
### Get hero by id ### Get hero by id
@ -219,20 +254,20 @@ Most web APIs support a _get by id_ request in the form `:baseURL/:id`.
Here, the _base URL_ is the `heroesURL` defined in the [Heroes and HTTP](tutorial/toh-pt6#heroes-and-http) section (`api/heroes`) and _id_ is Here, the _base URL_ is the `heroesURL` defined in the [Heroes and HTTP](tutorial/toh-pt6#heroes-and-http) section (`api/heroes`) and _id_ is
the number of the hero that you want to retrieve. For example, `api/heroes/11`. the number of the hero that you want to retrieve. For example, `api/heroes/11`.
Update the `HeroService` `getHero()` method with the following to make that request: Add a `HeroService.getHero()` method to make that request:
<code-example path="toh-pt6/src/app/hero.service.ts" region="getHero" header="src/app/hero.service.ts"></code-example> <code-example path="toh-pt6/src/app/hero.service.ts" region="getHero" header="src/app/hero.service.ts"></code-example>
There are three significant differences from `getHeroes()`: There are three significant differences from `getHeroes()`.
* `getHero()` constructs a request URL with the desired hero's id. * it constructs a request URL with the desired hero's id.
* The server should respond with a single hero rather than an array of heroes. * the server should respond with a single hero rather than an array of heroes.
* `getHero()` returns an `Observable<Hero>` ("_an observable of Hero objects_") * therefore, `getHero` returns an `Observable<Hero>` ("_an observable of Hero objects_")
rather than an observable of hero _arrays_ . rather than an observable of hero _arrays_ .
## Update heroes ## Update heroes
Edit a hero's name in the hero detail view. Edit a hero's name in the _hero detail_ view.
As you type, the hero name updates the heading at the top of the page. As you type, the hero name updates the heading at the top of the page.
But when you click the "go back button", the changes are lost. But when you click the "go back button", the changes are lost.
@ -244,21 +279,24 @@ binding that invokes a new component method named `save()`.
<code-example path="toh-pt6/src/app/hero-detail/hero-detail.component.html" region="save" header="src/app/hero-detail/hero-detail.component.html (save)"></code-example> <code-example path="toh-pt6/src/app/hero-detail/hero-detail.component.html" region="save" header="src/app/hero-detail/hero-detail.component.html (save)"></code-example>
In the `HeroDetail` component class, add the following `save()` method, which persists hero name changes using the hero service Add the following `save()` method, which persists hero name changes using the hero service
`updateHero()` method and then navigates back to the previous view. `updateHero()` method and then navigates back to the previous view.
<code-example path="toh-pt6/src/app/hero-detail/hero-detail.component.ts" region="save" header="src/app/hero-detail/hero-detail.component.ts (save)"></code-example> <code-example path="toh-pt6/src/app/hero-detail/hero-detail.component.ts" region="save" header="src/app/hero-detail/hero-detail.component.ts (save)"></code-example>
#### Add `HeroService.updateHero()` #### Add _HeroService.updateHero()_
The overall structure of the `updateHero()` method is similar to that of The overall structure of the `updateHero()` method is similar to that of
`getHeroes()`, but it uses `http.put()` to persist the changed hero `getHeroes()`, but it uses `http.put()` to persist the changed hero
on the server. Add the following to the `HeroService`. on the server.
<code-example path="toh-pt6/src/app/hero.service.ts" region="updateHero" header="src/app/hero.service.ts (update)"> <code-example
path="toh-pt6/src/app/hero.service.ts"
region="updateHero"
header="src/app/hero.service.ts (update)">
</code-example> </code-example>
The `HttpClient.put()` method takes three parameters: The `HttpClient.put()` method takes three parameters
* the URL * the URL
* the data to update (the modified hero in this case) * the data to update (the modified hero in this case)
* options * options
@ -266,19 +304,20 @@ The `HttpClient.put()` method takes three parameters:
The URL is unchanged. The heroes web API knows which hero to update by looking at the hero's `id`. The URL is unchanged. The heroes web API knows which hero to update by looking at the hero's `id`.
The heroes web API expects a special header in HTTP save requests. The heroes web API expects a special header in HTTP save requests.
That header is in the `httpOptions` constant defined in the `HeroService`. Add the following to the `HeroService` class. That header is in the `httpOptions` constant defined in the `HeroService`.
<code-example path="toh-pt6/src/app/hero.service.ts" region="http-options" header="src/app/hero.service.ts"> <code-example
path="toh-pt6/src/app/hero.service.ts"
region="http-options"
header="src/app/hero.service.ts">
</code-example> </code-example>
Refresh the browser, change a hero name and save your change. The `save()` Refresh the browser, change a hero name and save your change. Navigating to the previous view is implemented in the `save()` method defined in `HeroDetailComponent`.
method in `HeroDetailComponent`navigates to the previous view.
The hero now appears in the list with the changed name. The hero now appears in the list with the changed name.
## Add a new hero ## Add a new hero
To add a hero, this app only needs the hero's name. You can use an `<input>` To add a hero, this app only needs the hero's name. You can use an `input`
element paired with an add button. element paired with an add button.
Insert the following into the `HeroesComponent` template, just after Insert the following into the `HeroesComponent` template, just after
@ -286,26 +325,29 @@ the heading:
<code-example path="toh-pt6/src/app/heroes/heroes.component.html" region="add" header="src/app/heroes/heroes.component.html (add)"></code-example> <code-example path="toh-pt6/src/app/heroes/heroes.component.html" region="add" header="src/app/heroes/heroes.component.html (add)"></code-example>
In response to a click event, call the component's click handler, `add()`, and then In response to a click event, call the component's click handler and then
clear the input field so that it's ready for another name. Add the following to the clear the input field so that it's ready for another name.
`HeroesComponent` class:
<code-example path="toh-pt6/src/app/heroes/heroes.component.ts" region="add" header="src/app/heroes/heroes.component.ts (add)"></code-example> <code-example path="toh-pt6/src/app/heroes/heroes.component.ts" region="add" header="src/app/heroes/heroes.component.ts (add)"></code-example>
When the given name is non-blank, the handler creates a `Hero`-like object When the given name is non-blank, the handler creates a `Hero`-like object
from the name (it's only missing the `id`) and passes it to the services `addHero()` method. from the name (it's only missing the `id`) and passes it to the services `addHero()` method.
When `addHero()` saves successfully, the `subscribe()` callback When `addHero` saves successfully, the `subscribe` callback
receives the new hero and pushes it into to the `heroes` list for display. receives the new hero and pushes it into to the `heroes` list for display.
You'll write `HeroService.addHero` in the next section.
#### Add _HeroService.addHero()_
Add the following `addHero()` method to the `HeroService` class. Add the following `addHero()` method to the `HeroService` class.
<code-example path="toh-pt6/src/app/hero.service.ts" region="addHero" header="src/app/hero.service.ts (addHero)"></code-example> <code-example path="toh-pt6/src/app/hero.service.ts" region="addHero" header="src/app/hero.service.ts (addHero)"></code-example>
`addHero()` differs from `updateHero()` in two ways: `HeroService.addHero()` differs from `updateHero` in two ways.
* It calls `HttpClient.post()` instead of `put()`. * it calls `HttpClient.post()` instead of `put()`.
* It expects the server to generate an id for the new hero, * it expects the server to generate an id for the new hero,
which it returns in the `Observable<Hero>` to the caller. which it returns in the `Observable<Hero>` to the caller.
Refresh the browser and add some heroes. Refresh the browser and add some heroes.
@ -317,7 +359,7 @@ Each hero in the heroes list should have a delete button.
Add the following button element to the `HeroesComponent` template, after the hero Add the following button element to the `HeroesComponent` template, after the hero
name in the repeated `<li>` element. name in the repeated `<li>` element.
<code-example path="toh-pt6/src/app/heroes/heroes.component.html" header="src/app/hero.service.ts" region="delete"></code-example> <code-example path="toh-pt6/src/app/heroes/heroes.component.html" region="delete"></code-example>
The HTML for the list of heroes should look like this: The HTML for the list of heroes should look like this:
@ -327,7 +369,7 @@ To position the delete button at the far right of the hero entry,
add some CSS to the `heroes.component.css`. You'll find that CSS add some CSS to the `heroes.component.css`. You'll find that CSS
in the [final review code](#heroescomponent) below. in the [final review code](#heroescomponent) below.
Add the `delete()` handler to the component class. Add the `delete()` handler to the component.
<code-example path="toh-pt6/src/app/heroes/heroes.component.ts" region="delete" header="src/app/heroes/heroes.component.ts (delete)"></code-example> <code-example path="toh-pt6/src/app/heroes/heroes.component.ts" region="delete" header="src/app/heroes/heroes.component.ts (delete)"></code-example>
@ -337,12 +379,12 @@ The component's `delete()` method immediately removes the _hero-to-delete_ from
anticipating that the `HeroService` will succeed on the server. anticipating that the `HeroService` will succeed on the server.
There's really nothing for the component to do with the `Observable` returned by There's really nothing for the component to do with the `Observable` returned by
`heroService.delete()` **but it must subscribe anyway**. `heroService.delete()`. **It must subscribe anyway**.
<div class="alert is-important"> <div class="alert is-important">
If you neglect to `subscribe()`, the service will not send the delete request to the server. If you neglect to `subscribe()`, the service will not send the delete request to the server!
As a rule, an `Observable` _does nothing_ until something subscribes. As a rule, an `Observable` _does nothing_ until something subscribes!
Confirm this for yourself by temporarily removing the `subscribe()`, Confirm this for yourself by temporarily removing the `subscribe()`,
clicking "Dashboard", then clicking "Heroes". clicking "Dashboard", then clicking "Heroes".
@ -350,16 +392,18 @@ There's really nothing for the component to do with the `Observable` returned by
</div> </div>
Next, add a `deleteHero()` method to `HeroService` like this. #### Add _HeroService.deleteHero()_
Add a `deleteHero()` method to `HeroService` like this.
<code-example path="toh-pt6/src/app/hero.service.ts" region="deleteHero" header="src/app/hero.service.ts (delete)"></code-example> <code-example path="toh-pt6/src/app/hero.service.ts" region="deleteHero" header="src/app/hero.service.ts (delete)"></code-example>
Note the following key points: Note that
* `deleteHero()` calls `HttpClient.delete()`. * it calls `HttpClient.delete`.
* The URL is the heroes resource URL plus the `id` of the hero to delete. * the URL is the heroes resource URL plus the `id` of the hero to delete
* You don't send data as you did with `put()` and `post()`. * you don't send data as you did with `put` and `post`.
* You still send the `httpOptions`. * you still send the `httpOptions`.
Refresh the browser and try the new delete functionality. Refresh the browser and try the new delete functionality.
@ -369,36 +413,43 @@ In this last exercise, you learn to chain `Observable` operators together
so you can minimize the number of similar HTTP requests so you can minimize the number of similar HTTP requests
and consume network bandwidth economically. and consume network bandwidth economically.
You will add a heroes search feature to the Dashboard. You will add a *heroes search* feature to the *Dashboard*.
As the user types a name into a search box, As the user types a name into a search box,
you'll make repeated HTTP requests for heroes filtered by that name. you'll make repeated HTTP requests for heroes filtered by that name.
Your goal is to issue only as many requests as necessary. Your goal is to issue only as many requests as necessary.
#### `HeroService.searchHeroes()` #### _HeroService.searchHeroes_
Start by adding a `searchHeroes()` method to the `HeroService`. Start by adding a `searchHeroes` method to the `HeroService`.
<code-example path="toh-pt6/src/app/hero.service.ts" region="searchHeroes" header="src/app/hero.service.ts"> <code-example
path="toh-pt6/src/app/hero.service.ts"
region="searchHeroes"
header="src/app/hero.service.ts">
</code-example> </code-example>
The method returns immediately with an empty array if there is no search term. The method returns immediately with an empty array if there is no search term.
The rest of it closely resembles `getHeroes()`, the only significant difference being The rest of it closely resembles `getHeroes()`.
the URL, which includes a query string with the search term. The only significant difference is the URL,
which includes a query string with the search term.
### Add search to the Dashboard ### Add search to the Dashboard
Open the `DashboardComponent` template and Open the `DashboardComponent` _template_ and
add the hero search element, `<app-hero-search>`, to the bottom of the markup. Add the hero search element, `<app-hero-search>`, to the bottom of the `DashboardComponent` template.
<code-example path="toh-pt6/src/app/dashboard/dashboard.component.html" header="src/app/dashboard/dashboard.component.html" linenums="false"> <code-example
path="toh-pt6/src/app/dashboard/dashboard.component.html" header="src/app/dashboard/dashboard.component.html" linenums="false">
</code-example> </code-example>
This template looks a lot like the `*ngFor` repeater in the `HeroesComponent` template. This template looks a lot like the `*ngFor` repeater in the `HeroesComponent` template.
For this to work, the next step is to add a component with a selector that matches `<app-hero-search>`. Unfortunately, adding this element breaks the app.
Angular can't find a component with a selector that matches `<app-hero-search>`.
The `HeroSearchComponent` doesn't exist yet. Fix that.
### Create `HeroSearchComponent` ### Create _HeroSearchComponent_
Create a `HeroSearchComponent` with the CLI. Create a `HeroSearchComponent` with the CLI.
@ -406,60 +457,68 @@ Create a `HeroSearchComponent` with the CLI.
ng generate component hero-search ng generate component hero-search
</code-example> </code-example>
The CLI generates the three `HeroSearchComponent` files and adds the component to the `AppModule` declarations. The CLI generates the three `HeroSearchComponent` files and adds the component to the `AppModule` declarations
Replace the generated `HeroSearchComponent` template with an `<input>` and a list of matching search results, as follows. Replace the generated `HeroSearchComponent` _template_ with a text box and a list of matching search results like this.
<code-example path="toh-pt6/src/app/hero-search/hero-search.component.html" header="src/app/hero-search/hero-search.component.html"></code-example> <code-example path="toh-pt6/src/app/hero-search/hero-search.component.html" header="src/app/hero-search/hero-search.component.html"></code-example>
Add private CSS styles to `hero-search.component.css` Add private CSS styles to `hero-search.component.css`
as listed in the [final code review](#herosearchcomponent) below. as listed in the [final code review](#herosearchcomponent) below.
As the user types in the search box, an input event binding calls the As the user types in the search box, an *input* event binding calls the component's `search()`
component's `search()` method with the new search box value. method with the new search box value.
{@a asyncpipe} {@a asyncpipe}
### `AsyncPipe` ### _AsyncPipe_
The `*ngFor` repeats hero objects. Notice that the `*ngFor` iterates over a list called `heroes$`, not `heroes`. The `$` is a convention that indicates `heroes$` is an `Observable`, not an array. As expected, the `*ngFor` repeats hero objects.
Look closely and you'll see that the `*ngFor` iterates over a list called `heroes$`, not `heroes`.
<code-example path="toh-pt6/src/app/hero-search/hero-search.component.html" header="src/app/hero-search/hero-search.component.html" region="async"></code-example> <code-example path="toh-pt6/src/app/hero-search/hero-search.component.html" region="async"></code-example>
Since `*ngFor` can't do anything with an `Observable`, use the The `$` is a convention that indicates `heroes$` is an `Observable`, not an array.
pipe character (`|`) followed by `async`. This identifies Angular's `AsyncPipe` and subscribes to an `Observable` automatically so you won't have to
The `*ngFor` can't do anything with an `Observable`.
But there's also a pipe character (`|`) followed by `async`,
which identifies Angular's `AsyncPipe`.
The `AsyncPipe` subscribes to an `Observable` automatically so you won't have to
do so in the component class. do so in the component class.
### Edit the `HeroSearchComponent` class ### Fix the _HeroSearchComponent_ class
Replace the generated `HeroSearchComponent` class and metadata as follows. Replace the generated `HeroSearchComponent` class and metadata as follows.
<code-example path="toh-pt6/src/app/hero-search/hero-search.component.ts" header="src/app/hero-search/hero-search.component.ts"></code-example> <code-example path="toh-pt6/src/app/hero-search/hero-search.component.ts" header="src/app/hero-search/hero-search.component.ts"></code-example>
Notice the declaration of `heroes$` as an `Observable`: Notice the declaration of `heroes$` as an `Observable`
<code-example
<code-example path="toh-pt6/src/app/hero-search/hero-search.component.ts" header="src/app/hero-search/hero-search.component.ts" region="heroes-stream"> path="toh-pt6/src/app/hero-search/hero-search.component.ts"
region="heroes-stream">
</code-example> </code-example>
You'll set it in [`ngOnInit()`](#search-pipe). You'll set it in [`ngOnInit()`](#search-pipe).
Before you do, focus on the definition of `searchTerms`. Before you do, focus on the definition of `searchTerms`.
### The `searchTerms` RxJS subject ### The _searchTerms_ RxJS subject
The `searchTerms` property is an RxJS `Subject`. The `searchTerms` property is declared as an RxJS `Subject`.
<code-example path="toh-pt6/src/app/hero-search/hero-search.component.ts" header="src/app/hero-search/hero-search.component.ts" region="searchTerms"></code-example> <code-example path="toh-pt6/src/app/hero-search/hero-search.component.ts" region="searchTerms"></code-example>
A `Subject` is both a source of observable values and an `Observable` itself. A `Subject` is both a source of _observable_ values and an `Observable` itself.
You can subscribe to a `Subject` as you would any `Observable`. You can subscribe to a `Subject` as you would any `Observable`.
You can also push values into that `Observable` by calling its `next(value)` method You can also push values into that `Observable` by calling its `next(value)` method
as the `search()` method does. as the `search()` method does.
The event binding to the textbox's `input` event calls the `search()` method. The `search()` method is called via an _event binding_ to the
textbox's `input` event.
<code-example path="toh-pt6/src/app/hero-search/hero-search.component.html" header="src/app/hero-search/hero-search.component.html" region="input"></code-example> <code-example path="toh-pt6/src/app/hero-search/hero-search.component.html" region="input"></code-example>
Every time the user types in the textbox, the binding calls `search()` with the textbox value, a "search term". Every time the user types in the textbox, the binding calls `search()` with the textbox value, a "search term".
The `searchTerms` becomes an `Observable` emitting a steady stream of search terms. The `searchTerms` becomes an `Observable` emitting a steady stream of search terms.
@ -469,24 +528,28 @@ The `searchTerms` becomes an `Observable` emitting a steady stream of search ter
### Chaining RxJS operators ### Chaining RxJS operators
Passing a new search term directly to the `searchHeroes()` after every user keystroke would create an excessive amount of HTTP requests, Passing a new search term directly to the `searchHeroes()` after every user keystroke would create an excessive amount of HTTP requests,
taxing server resources and burning through data plans. taxing server resources and burning through the cellular network data plan.
Instead, the `ngOnInit()` method pipes the `searchTerms` observable through a sequence of RxJS operators that reduce the number of calls to the `searchHeroes()`, Instead, the `ngOnInit()` method pipes the `searchTerms` observable through a sequence of RxJS operators that reduce the number of calls to the `searchHeroes()`,
ultimately returning an observable of timely hero search results (each a `Hero[]`). ultimately returning an observable of timely hero search results (each a `Hero[]`).
Here's a closer look at the code. Here's the code.
<code-example path="toh-pt6/src/app/hero-search/hero-search.component.ts" header="src/app/hero-search/hero-search.component.ts" region="search"> <code-example
path="toh-pt6/src/app/hero-search/hero-search.component.ts"
region="search">
</code-example> </code-example>
Each operator works as follows:
* `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds * `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds
before passing along the latest string. You'll never make requests more frequently than 300ms. before passing along the latest string. You'll never make requests more frequently than 300ms.
* `distinctUntilChanged()` ensures that a request is sent only if the filter text changed. * `distinctUntilChanged()` ensures that a request is sent only if the filter text changed.
* `switchMap()` calls the search service for each search term that makes it through `debounce()` and `distinctUntilChanged()`.
* `switchMap()` calls the search service for each search term that makes it through `debounce` and `distinctUntilChanged`.
It cancels and discards previous search observables, returning only the latest search service observable. It cancels and discards previous search observables, returning only the latest search service observable.
@ -500,7 +563,7 @@ It cancels and discards previous search observables, returning only the latest s
`switchMap()` preserves the original request order while returning only the observable from the most recent HTTP method call. `switchMap()` preserves the original request order while returning only the observable from the most recent HTTP method call.
Results from prior calls are canceled and discarded. Results from prior calls are canceled and discarded.
Note that canceling a previous `searchHeroes()` Observable Note that _canceling_ a previous `searchHeroes()` _Observable_
doesn't actually abort a pending HTTP request. doesn't actually abort a pending HTTP request.
Unwanted results are simply discarded before they reach your application code. Unwanted results are simply discarded before they reach your application code.
@ -527,7 +590,7 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
{@a heroservice} {@a heroservice}
{@a inmemorydataservice} {@a inmemorydataservice}
{@a appmodule} {@a appmodule}
#### `HeroService`, `InMemoryDataService`, `AppModule` #### _HeroService_, _InMemoryDataService_, _AppModule_
<code-tabs> <code-tabs>
<code-pane <code-pane
@ -545,7 +608,7 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
</code-tabs> </code-tabs>
{@a heroescomponent} {@a heroescomponent}
#### `HeroesComponent` #### _HeroesComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
@ -563,7 +626,7 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
</code-tabs> </code-tabs>
{@a herodetailcomponent} {@a herodetailcomponent}
#### `HeroDetailComponent` #### _HeroDetailComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
@ -577,7 +640,7 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
</code-tabs> </code-tabs>
{@a dashboardcomponent} {@a dashboardcomponent}
#### `DashboardComponent` #### _DashboardComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
@ -587,7 +650,7 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
</code-tabs> </code-tabs>
{@a herosearchcomponent} {@a herosearchcomponent}
#### `HeroSearchComponent` #### _HeroSearchComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane

View File

@ -10,22 +10,17 @@ module.exports = function (config) {
require('karma-chrome-launcher'), require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'), require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'), require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma'), require('@angular-devkit/build-angular/plugins/karma')
{'reporter:jasmine-seed': ['type', JasmineSeedReporter]},
], ],
client: { client: {
clearContext: false, // leave Jasmine Spec Runner output visible in browser clearContext: false // leave Jasmine Spec Runner output visible in browser
jasmine: {
random: true,
seed: '',
},
}, },
coverageIstanbulReporter: { coverageIstanbulReporter: {
dir: require('path').join(__dirname, './coverage/site'), dir: require('path').join(__dirname, './coverage/site'),
reports: ['html', 'lcovonly', 'text-summary'], reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true, fixWebpackSourcePaths: true
}, },
reporters: ['progress', 'kjhtml', 'jasmine-seed'], reporters: ['progress', 'kjhtml'],
port: 9876, port: 9876,
colors: true, colors: true,
logLevel: config.LOG_INFO, logLevel: config.LOG_INFO,
@ -33,18 +28,6 @@ module.exports = function (config) {
browsers: ['Chrome'], browsers: ['Chrome'],
browserNoActivityTimeout: 60000, browserNoActivityTimeout: 60000,
singleRun: false, singleRun: false,
restartOnFileChange: true, restartOnFileChange: true
}); });
}; };
// Helpers
function JasmineSeedReporter(baseReporterDecorator) {
baseReporterDecorator(this);
this.onBrowserComplete = (browser, result) => {
const seed = result.order && result.order.random && result.order.seed;
if (seed) this.write(`${browser}: Randomized with seed ${seed}.\n`);
};
this.onRunComplete = () => undefined;
}

View File

@ -19,7 +19,7 @@
"build-local": "yarn ~~build", "build-local": "yarn ~~build",
"prebuild-with-ivy": "yarn setup-local && node scripts/switch-to-ivy", "prebuild-with-ivy": "yarn setup-local && node scripts/switch-to-ivy",
"build-with-ivy": "yarn ~~build", "build-with-ivy": "yarn ~~build",
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js f99913e9f", "extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js 7da10691d",
"lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint", "lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint",
"test": "yarn check-env && ng test", "test": "yarn check-env && ng test",
"pree2e": "yarn check-env && yarn update-webdriver", "pree2e": "yarn check-env && yarn update-webdriver",
@ -33,10 +33,8 @@
"set-opensearch-url": "node --eval \"const sh = require('shelljs'); sh.set('-e'); sh.sed('-i', /PLACEHOLDER_URL/g, process.argv[1], 'dist/assets/opensearch.xml');\"", "set-opensearch-url": "node --eval \"const sh = require('shelljs'); sh.set('-e'); sh.sed('-i', /PLACEHOLDER_URL/g, process.argv[1], 'dist/assets/opensearch.xml');\"",
"presmoke-tests": "yarn update-webdriver", "presmoke-tests": "yarn update-webdriver",
"smoke-tests": "protractor tests/deployment/e2e/protractor.conf.js --suite smoke --baseUrl", "smoke-tests": "protractor tests/deployment/e2e/protractor.conf.js --suite smoke --baseUrl",
"test-a11y-score": "node scripts/test-aio-a11y", "test-pwa-score": "node scripts/test-pwa-score",
"test-a11y-score-localhost": "run-p --race \"~~light-server -s dist -p 4200 --quiet\" \"test-a11y-score http://localhost:4200\" --", "test-pwa-score-localhost": "run-p --race \"~~http-server dist -p 4200 --silent\" \"test-pwa-score http://localhost:4200 {1} {2}\" --",
"test-pwa-score": "run-s \"~~audit-web-app {1} all:0,pwa:{2} {3}\" --",
"test-pwa-score-localhost": "run-p --race \"~~light-server -s dist -p 4200 --quiet\" \"test-pwa-score http://localhost:4200 {1} {2}\" --",
"example-e2e": "yarn example-check-local && node ./tools/examples/run-example-e2e", "example-e2e": "yarn example-check-local && node ./tools/examples/run-example-e2e",
"example-lint": "tslint --config \"content/examples/tslint.json\" \"content/examples/**/*.ts\" --exclude \"content/examples/styleguide/**/*.avoid.ts\"", "example-lint": "tslint --config \"content/examples/tslint.json\" \"content/examples/**/*.ts\" --exclude \"content/examples/styleguide/**/*.avoid.ts\"",
"example-use-local": "node tools/ng-packages-installer overwrite ./tools/examples/shared --debug", "example-use-local": "node tools/ng-packages-installer overwrite ./tools/examples/shared --debug",
@ -66,16 +64,15 @@
"generate-zips": "node ./tools/example-zipper/generateZips", "generate-zips": "node ./tools/example-zipper/generateZips",
"build-404-page": "node scripts/build-404-page", "build-404-page": "node scripts/build-404-page",
"update-webdriver": "webdriver-manager update --standalone false --gecko false $CI_CHROMEDRIVER_VERSION_ARG", "update-webdriver": "webdriver-manager update --standalone false --gecko false $CI_CHROMEDRIVER_VERSION_ARG",
"~~audit-web-app": "node scripts/audit-web-app",
"~~check-env": "node scripts/check-environment", "~~check-env": "node scripts/check-environment",
"~~clean-generated": "node --eval \"require('shelljs').rm('-rf', 'src/generated')\"", "~~clean-generated": "node --eval \"require('shelljs').rm('-rf', 'src/generated')\"",
"~~build": "ng build --configuration=stable", "~~build": "ng build --configuration=stable",
"post~~build": "yarn build-404-page", "post~~build": "yarn build-404-page",
"~~light-server": "light-server --bind=localhost --historyindex=/index.html --no-reload" "~~http-server": "http-server"
}, },
"engines": { "engines": {
"node": ">=10.9.0 <11.0.0", "node": ">=10.9.0 <11.0.0",
"yarn": ">=1.12.1 <=1.16.0" "yarn": ">=1.12.1 <=1.14.0"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
@ -109,13 +106,13 @@
"archiver": "^1.3.0", "archiver": "^1.3.0",
"canonical-path": "1.0.0", "canonical-path": "1.0.0",
"chalk": "^2.1.0", "chalk": "^2.1.0",
"chrome-launcher": "^0.10.7", "chrome-launcher": "^0.10.5",
"cjson": "^0.5.0", "cjson": "^0.5.0",
"codelyzer": "^5.0.0", "codelyzer": "^5.0.0",
"cross-spawn": "^5.1.0", "cross-spawn": "^5.1.0",
"css-selector-parser": "^1.3.0", "css-selector-parser": "^1.3.0",
"dgeni": "^0.4.11", "dgeni": "^0.4.11",
"dgeni-packages": "^0.27.5", "dgeni-packages": "^0.27.1",
"entities": "^1.1.1", "entities": "^1.1.1",
"eslint": "^3.19.0", "eslint": "^3.19.0",
"eslint-plugin-jasmine": "^2.2.0", "eslint-plugin-jasmine": "^2.2.0",
@ -126,23 +123,24 @@
"hast-util-is-element": "^1.0.0", "hast-util-is-element": "^1.0.0",
"hast-util-to-string": "^1.0.0", "hast-util-to-string": "^1.0.0",
"html": "^1.0.0", "html": "^1.0.0",
"http-server": "^0.11.1",
"ignore": "^3.3.3", "ignore": "^3.3.3",
"image-size": "^0.5.1", "image-size": "^0.5.1",
"jasmine": "^3.4.0", "jasmine": "^2.6.0",
"jasmine-core": "^3.4.0", "jasmine-core": "^2.8.0",
"jasmine-spec-reporter": "^4.2.1", "jasmine-marbles": "^0.3.1",
"jasmine-spec-reporter": "^4.1.0",
"jasmine-ts": "^0.2.1", "jasmine-ts": "^0.2.1",
"jsdom": "^9.12.0", "jsdom": "^9.12.0",
"json-schema-traverse": "^0.4.1", "json-schema-traverse": "^0.4.1",
"json5": "^1.0.1", "json5": "^1.0.1",
"karma": "^4.1.0", "karma": "^1.7.0",
"karma-chrome-launcher": "^2.2.0", "karma-chrome-launcher": "^2.1.1",
"karma-cli": "^2.0.0", "karma-cli": "^1.0.1",
"karma-coverage-istanbul-reporter": "^2.0.5", "karma-coverage-istanbul-reporter": "^1.3.0",
"karma-jasmine": "^2.0.1", "karma-jasmine": "^1.1.0",
"karma-jasmine-html-reporter": "^1.4.2", "karma-jasmine-html-reporter": "^0.2.2",
"light-server": "^2.6.2", "lighthouse": "^4.3.0",
"lighthouse": "^5.1.0",
"lighthouse-logger": "^1.2.0", "lighthouse-logger": "^1.2.0",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"lunr": "^2.1.0", "lunr": "^2.1.0",

View File

@ -16,8 +16,8 @@
"uncompressed": { "uncompressed": {
"runtime-es5": 3042, "runtime-es5": 3042,
"runtime-es2015": 3048, "runtime-es2015": 3048,
"main-es5": 511036, "main-es5": 504845,
"main-es2015": 450486, "main-es2015": 443921,
"polyfills-es5": 130136, "polyfills-es5": 130136,
"polyfills-es2015": 52931 "polyfills-es2015": 52931
} }
@ -28,8 +28,8 @@
"uncompressed": { "uncompressed": {
"runtime-es5": 2932, "runtime-es5": 2932,
"runtime-es2015": 2938, "runtime-es2015": 2938,
"main-es5": 565073, "main-es5": 563201,
"main-es2015": 583108, "main-es2015": 580852,
"polyfills-es5": 130136, "polyfills-es5": 130136,
"polyfills-es2015": 52931 "polyfills-es2015": 52931
} }

View File

@ -1,179 +0,0 @@
#!/bin/env node
'use strict';
/**
* Usage:
* ```sh
* node scripts/audit-web-app <url> <min-scores> [<log-file>]
* ```
*
* Runs audits against the specified URL on specific categories (accessibility, best practices, performance, PWA, SEO).
* It fails, if the score in any category is below the score specified in `<min-scores>`. (Only runs audits for the
* specified categories.)
*
* `<min-scores>` is either a number (in which case it is interpreted as `all:<min-score>`) or a list of comma-separated
* strings of the form `key:value`, where `key` is one of `accessibility`, `best-practices`, `performance`, `pwa`, `seo`
* or `all` and `value` is a number (between 0 and 100).
*
* Examples:
* - `95` _(Same as `all:95`.)_
* - `all:95` _(Run audits for all categories and require a score of 95 or higher.)_
* - `all:95,pwa:100` _(Same as `all:95`, except that a scope of 100 is required for the `pwa` category.)_
* - `performance:90` _(Only run audits for the `performance` category and require a score of 90 or higher.)_
*
* If `<log-file>` is defined, the full results will be logged there.
*
* (Skips HTTPS-related audits, when run for an HTTP URL.)
*/
// Imports
const chromeLauncher = require('chrome-launcher');
const lighthouse = require('lighthouse');
const printer = require('lighthouse/lighthouse-cli/printer');
const logger = require('lighthouse-logger');
// Constants
const AUDIT_CATEGORIES = ['accessibility', 'best-practices', 'performance', 'pwa', 'seo'];
const CHROME_LAUNCH_OPTS = {chromeFlags: ['--headless']};
const LIGHTHOUSE_FLAGS = {logLevel: process.env.CI ? 'error' : 'info'}; // Be less verbose on CI.
const SKIPPED_HTTPS_AUDITS = ['redirects-http', 'uses-http2'];
const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer';
const WAIT_FOR_SW_DELAY = 5000;
// Run
_main(process.argv.slice(2));
// Functions - Definitions
async function _main(args) {
const {url, minScores, logFile} = parseInput(args);
const isOnHttp = /^http:/.test(url);
const lhFlags = {...LIGHTHOUSE_FLAGS, onlyCategories: Object.keys(minScores).sort()};
const lhConfig = {
extends: 'lighthouse:default',
// Since the Angular ServiceWorker waits for the app to stabilize before registering,
// wait a few seconds after load to allow Lighthouse to reliably detect it.
passes: [{passName: 'defaultPass', pauseAfterLoadMs: WAIT_FOR_SW_DELAY}],
};
console.log(`Running web-app audits for '${url}'...`);
console.log(` Audit categories: ${lhFlags.onlyCategories.join(', ')}`);
// If testing on HTTP, skip HTTPS-specific tests.
// (Note: Browsers special-case localhost and run ServiceWorker even on HTTP.)
if (isOnHttp) skipHttpsAudits(lhConfig);
logger.setLevel(lhFlags.logLevel);
try {
console.log('');
const startTime = Date.now();
const results = await launchChromeAndRunLighthouse(url, lhFlags, lhConfig);
const success = await processResults(results, minScores, logFile);
console.log(`\n(Completed in ${((Date.now() - startTime) / 1000).toFixed(1)}s.)\n`);
if (!success) {
throw new Error('One or more scores are too low.');
}
} catch (err) {
onError(err);
}
}
function formatScore(score) {
return `${(score * 100).toFixed(0).padStart(3)}`;
}
async function launchChromeAndRunLighthouse(url, flags, config) {
const chrome = await chromeLauncher.launch(CHROME_LAUNCH_OPTS);
flags.port = chrome.port;
try {
return await lighthouse(url, flags, config);
} finally {
await chrome.kill();
}
}
function onError(err) {
console.error(err);
console.error('');
process.exit(1);
}
function parseInput(args) {
const [url, minScoresRaw, logFile] = args;
if (!url) {
onError('Invalid arguments: <url> not specified.');
} else if (!minScoresRaw) {
onError('Invalid arguments: <min-scores> not specified.');
}
const minScores = parseMinScores(minScoresRaw || '');
const unknownCategories = Object.keys(minScores).filter(cat => !AUDIT_CATEGORIES.includes(cat));
const allValuesValid = Object.values(minScores).every(x => (0 <= x) && (x <= 1));
if (unknownCategories.length > 0) {
onError(`Invalid arguments: <min-scores> contains unknown category(-ies): ${unknownCategories.join(', ')}`);
} else if (!allValuesValid) {
onError(`Invalid arguments: <min-scores> has non-numeric or out-of-range values: ${minScoresRaw}`);
}
return {url, minScores, logFile};
}
function parseMinScores(raw) {
const minScores = {};
if (/^\d+$/.test(raw)) {
raw = `all:${raw}`;
}
raw.
split(',').
map(x => x.split(':')).
forEach(([key, val]) => minScores[key] = Number(val) / 100);
if (minScores.hasOwnProperty('all')) {
AUDIT_CATEGORIES.forEach(cat => minScores.hasOwnProperty(cat) || (minScores[cat] = minScores.all));
delete minScores.all;
}
return minScores;
}
async function processResults(results, minScores, logFile) {
const lhVersion = results.lhr.lighthouseVersion;
const categories = results.lhr.categories;
const report = results.report;
if (logFile) {
console.log(`\nSaving results in '${logFile}'...`);
console.log(` LightHouse viewer: ${VIEWER_URL}`);
await printer.write(report, printer.OutputMode.json, logFile);
}
console.log(`\nLighthouse version: ${lhVersion}`);
console.log('\nAudit results:');
const maxTitleLen = Math.max(...Object.values(categories).map(({title}) => title.length));
const success = Object.keys(categories).sort().reduce((aggr, cat) => {
const {title, score} = categories[cat];
const paddedTitle = `${title}:`.padEnd(maxTitleLen + 1);
const minScore = minScores[cat];
const passed = !isNaN(score) && (score >= minScore);
console.log(
` - ${paddedTitle} ${formatScore(score)} (Required: ${formatScore(minScore)}) ${passed ? 'OK' : 'FAILED'}`);
return aggr && passed;
}, true);
return success;
}
function skipHttpsAudits(config) {
console.log(` Skipping HTTPS-related audits: ${SKIPPED_HTTPS_AUDITS.join(', ')}`);
config.settings = {...config.settings, skipAudits: SKIPPED_HTTPS_AUDITS};
}

View File

@ -1,38 +0,0 @@
#!/bin/env node
'use strict';
/**
* Usage:
* ```sh
* node scripts/test-aio-a11y <origin>
* ```
*
* Runs accessibility audits on several (pre-defined) pages on the specified origin. It fails, if
* the score for any page is below the minimum (see `MIN_SCORES_PER_PAGE` below).
*
* `<origin>` is the origin (scheme + hostname + port) of an angular.io deployment. It can be remote
* (e.g. `https://next.angular.io`) or local (e.g. `http://localhost:4200`).
*/
// Imports
const sh = require('shelljs');
sh.set('-e');
// Constants
const MIN_SCORES_PER_PAGE = {
'': 100,
'api': 100,
'api/core/Directive': 90,
'cli': 91,
'cli/add': 91,
'docs': 100,
'guide/docs-style-guide': 88,
'start': 90,
};
// Run
const auditWebAppCmd = `"${process.execPath}" "${__dirname}/audit-web-app"`;
const origin = process.argv[2];
for (const [page, minScore] of Object.entries(MIN_SCORES_PER_PAGE)) {
sh.exec(`${auditWebAppCmd} ${origin}/${page} accessibility:${minScore}`);
}

View File

@ -25,8 +25,5 @@ set +x -eu -o pipefail
# Run PWA-score tests. # Run PWA-score tests.
yarn test-pwa-score "$targetUrl" "$minPwaScore" yarn test-pwa-score "$targetUrl" "$minPwaScore"
# Run a11y tests.
yarn test-a11y-score "$targetUrl"
echo -e "\nAll checks passed!" echo -e "\nAll checks passed!"
) )

View File

@ -0,0 +1,135 @@
#!/bin/env node
/**
* Usage:
* ```sh
* node scripts/test-pwa-score <url> <min-score> [<log-file>]
* ```
*
* Fails if the score is below `<min-score>`.
* If `<log-file>` is defined, the full results will be logged there.
*
* (Skips HTTPS-related audits, when run for HTTP URL.)
*/
// Imports
const chromeLauncher = require('chrome-launcher');
const lighthouse = require('lighthouse');
const printer = require('lighthouse/lighthouse-cli/printer');
const logger = require('lighthouse-logger');
// Constants
const CHROME_LAUNCH_OPTS = {};
const LIGHTHOUSE_FLAGS = {logLevel: 'info'};
const SKIPPED_HTTPS_AUDITS = ['redirects-http'];
const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/';
const WAIT_FOR_SW_DELAY = 5000;
// Be less verbose on CI.
if (process.env.CI) {
LIGHTHOUSE_FLAGS.logLevel = 'error';
}
// Run
_main(process.argv.slice(2));
// Functions - Definitions
async function _main(args) {
const {url, minScore, logFile} = parseInput(args);
const isOnHttp = /^http:/.test(url);
const config = {
extends: 'lighthouse:default',
// Since the Angular ServiceWorker waits for the app to stabilize before registering,
// wait a few seconds after load to allow Lighthouse to reliably detect it.
passes: [{passName: 'defaultPass', pauseAfterLoadMs: WAIT_FOR_SW_DELAY}],
}
console.log(`Running PWA audit for '${url}'...`);
// If testing on HTTP, skip HTTPS-specific tests.
// (Note: Browsers special-case localhost and run ServiceWorker even on HTTP.)
if (isOnHttp) skipHttpsAudits(config);
logger.setLevel(LIGHTHOUSE_FLAGS.logLevel);
try {
const results = await launchChromeAndRunLighthouse(url, LIGHTHOUSE_FLAGS, config);
const score = await processResults(results, logFile);
evaluateScore(minScore, score);
} catch (err) {
onError(err);
}
}
function evaluateScore(expectedScore, actualScore) {
console.log('\nLighthouse PWA score:');
console.log(` - Expected: ${expectedScore.toFixed(0).padStart(3)} / 100 (or higher)`);
console.log(` - Actual: ${actualScore.toFixed(0).padStart(3)} / 100\n`);
if (isNaN(actualScore) || (actualScore < expectedScore)) {
throw new Error(`PWA score is too low. (${actualScore} < ${expectedScore})`);
}
}
async function launchChromeAndRunLighthouse(url, flags, config) {
const chrome = await chromeLauncher.launch(CHROME_LAUNCH_OPTS);
flags.port = chrome.port;
try {
return await lighthouse(url, flags, config);
} finally {
await chrome.kill();
}
}
function onError(err) {
console.error(err);
process.exit(1);
}
function parseInput(args) {
const url = args[0];
const minScore = Number(args[1]);
const logFile = args[2];
if (!url) {
onError('Invalid arguments: <URL> not specified.');
} else if (isNaN(minScore)) {
onError('Invalid arguments: <MIN_SCORE> not specified or not a number.');
}
return {url, minScore, logFile};
}
async function processResults(results, logFile) {
const lhVersion = results.lhr.lighthouseVersion;
const categories = results.lhr.categories;
const report = results.report;
if (logFile) {
console.log(`\nSaving results in '${logFile}'...`);
console.log(`(LightHouse viewer: ${VIEWER_URL})`);
await printer.write(report, printer.OutputMode.json, logFile);
}
const categoryData = Object.keys(categories).map(name => categories[name]);
const maxTitleLen = Math.max(...categoryData.map(({title}) => title.length));
console.log(`\nLighthouse version: ${lhVersion}`);
console.log('\nAudit scores:');
categoryData.forEach(({title, score}) => {
const paddedTitle = `${title}:`.padEnd(maxTitleLen + 1);
const paddedScore = (score * 100).toFixed(0).padStart(3);
console.log(` - ${paddedTitle} ${paddedScore} / 100`);
});
return categories.pwa.score * 100;
}
function skipHttpsAudits(config) {
console.info(`Skipping HTTPS-related audits (${SKIPPED_HTTPS_AUDITS.join(', ')})...`);
const settings = config.settings || (config.settings = {});
settings.skipAudits = SKIPPED_HTTPS_AUDITS;
}

View File

@ -630,11 +630,6 @@ describe('AppComponent', () => {
}; };
beforeEach(() => {
tocContainer = null;
toc = null;
});
it('should show/hide `<aio-toc>` based on `hasFloatingToc`', () => { it('should show/hide `<aio-toc>` based on `hasFloatingToc`', () => {
expect(tocContainer).toBeFalsy(); expect(tocContainer).toBeFalsy();
expect(toc).toBeFalsy(); expect(toc).toBeFalsy();

View File

@ -40,7 +40,6 @@ describe('AnnouncementBarComponent', () => {
it('should make a single request to the server', () => { it('should make a single request to the server', () => {
component.ngOnInit(); component.ngOnInit();
httpMock.expectOne('generated/announcements.json'); httpMock.expectOne('generated/announcements.json');
expect().nothing(); // Prevent jasmine from complaining about no expectations.
}); });
it('should set the announcement to the first "live" one in the list loaded from `announcements.json`', () => { it('should set the announcement to the first "live" one in the list loaded from `announcements.json`', () => {

View File

@ -15,7 +15,7 @@
</aio-select> </aio-select>
<div class="form-search"> <div class="form-search">
<input #filter placeholder="Filter" (input)="setQuery($event.target.value)" aria-label="Filter Search"> <input #filter placeholder="Filter" (input)="setQuery($event.target.value)">
<i class="material-icons">search</i> <i class="material-icons">search</i>
</div> </div>
</div> </div>

View File

@ -29,7 +29,6 @@ describe('ApiService', () => {
it('should not immediately connect to the server', () => { it('should not immediately connect to the server', () => {
httpMock.expectNone({}); httpMock.expectNone({});
expect().nothing(); // Prevent jasmine from complaining about no expectations.
}); });
it('subscribers should be completed/unsubscribed when service destroyed', () => { it('subscribers should be completed/unsubscribed when service destroyed', () => {
@ -92,7 +91,6 @@ describe('ApiService', () => {
it('should connect to the server w/ expected URL', () => { it('should connect to the server w/ expected URL', () => {
service.fetchSections(); service.fetchSections();
httpMock.expectOne('generated/docs/api/api-list.json'); httpMock.expectOne('generated/docs/api/api-list.json');
expect().nothing(); // Prevent jasmine from complaining about no expectations.
}); });
it('should refresh the #sections observable w/ new content on second call', () => { it('should refresh the #sections observable w/ new content on second call', () => {

View File

@ -5,8 +5,6 @@ import { CodeExampleComponent } from './code-example.component';
import { CodeExampleModule } from './code-example.module'; import { CodeExampleModule } from './code-example.module';
import { Logger } from 'app/shared/logger.service'; import { Logger } from 'app/shared/logger.service';
import { MockLogger } from 'testing/logger.service'; import { MockLogger } from 'testing/logger.service';
import { MockPrettyPrinter } from 'testing/pretty-printer.service';
import { PrettyPrinter } from './pretty-printer.service';
describe('CodeExampleComponent', () => { describe('CodeExampleComponent', () => {
let hostComponent: HostComponent; let hostComponent: HostComponent;
@ -21,7 +19,6 @@ describe('CodeExampleComponent', () => {
], ],
providers: [ providers: [
{ provide: Logger, useClass: MockLogger }, { provide: Logger, useClass: MockLogger },
{ provide: PrettyPrinter, useClass: MockPrettyPrinter },
] ]
}); });

View File

@ -2,12 +2,10 @@ import { Component, ViewChild, NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Logger } from 'app/shared/logger.service'; import { Logger } from 'app/shared/logger.service';
import { MockLogger } from 'testing/logger.service'; import { MockLogger } from 'testing/logger.service';
import { MockPrettyPrinter } from 'testing/pretty-printer.service';
import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { CodeTabsComponent } from './code-tabs.component'; import { CodeTabsComponent } from './code-tabs.component';
import { CodeTabsModule } from './code-tabs.module'; import { CodeTabsModule } from './code-tabs.module';
import { PrettyPrinter } from './pretty-printer.service';
describe('CodeTabsComponent', () => { describe('CodeTabsComponent', () => {
let fixture: ComponentFixture<HostComponent>; let fixture: ComponentFixture<HostComponent>;
@ -21,7 +19,6 @@ describe('CodeTabsComponent', () => {
schemas: [ NO_ERRORS_SCHEMA ], schemas: [ NO_ERRORS_SCHEMA ],
providers: [ providers: [
{ provide: Logger, useClass: MockLogger }, { provide: Logger, useClass: MockLogger },
{ provide: PrettyPrinter, useClass: MockPrettyPrinter },
] ]
}); });

View File

@ -1,104 +1,114 @@
import { Component, ViewChild, AfterViewInit } from '@angular/core'; import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { first } from 'rxjs/operators';
import { CodeComponent } from './code.component'; import { CodeComponent } from './code.component';
import { CodeModule } from './code.module'; import { CodeModule } from './code.module';
import { CopierService } from 'app/shared//copier.service'; import { CopierService } from 'app/shared//copier.service';
import { Logger } from 'app/shared/logger.service'; import { Logger } from 'app/shared/logger.service';
import { MockPrettyPrinter } from 'testing/pretty-printer.service';
import { PrettyPrinter } from './pretty-printer.service'; import { PrettyPrinter } from './pretty-printer.service';
const oneLineCode = 'const foo = "bar";'; const oneLineCode = 'const foo = "bar";';
const smallMultiLineCode = const smallMultiLineCode = `
`&lt;hero-details&gt; &lt;hero-details&gt;
&lt;h2&gt;Bah Dah Bing&lt;/h2&gt; &lt;h2&gt;Bah Dah Bing&lt;/h2&gt;
&lt;hero-team&gt; &lt;hero-team&gt;
&lt;h3&gt;NYC Team&lt;/h3&gt; &lt;h3&gt;NYC Team&lt;/h3&gt;
&lt;/hero-team&gt; &lt;/hero-team&gt;
&lt;/hero-details&gt;`; &lt;/hero-details&gt;`;
const bigMultiLineCode = `${smallMultiLineCode}\n${smallMultiLineCode}\n${smallMultiLineCode}`; const bigMultiLineCode = smallMultiLineCode + smallMultiLineCode + smallMultiLineCode;
describe('CodeComponent', () => { describe('CodeComponent', () => {
let hostComponent: HostComponent; let hostComponent: HostComponent;
let fixture: ComponentFixture<HostComponent>; let fixture: ComponentFixture<HostComponent>;
// WARNING: Chance of cross-test pollution
// CodeComponent injects PrettyPrintService
// Once PrettyPrintService runs once _anywhere_, its ctor loads `prettify.js`
// which sets `window['prettyPrintOne']`
// That global survives these tests unless
// we take strict measures to wipe it out in the `afterAll`
// and make sure THAT runs after the tests by making component creation async
afterAll(() => {
delete (window as any)['prettyPrint'];
delete (window as any)['prettyPrintOne'];
});
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ NoopAnimationsModule, CodeModule ], imports: [ NoopAnimationsModule, CodeModule ],
declarations: [ HostComponent ], declarations: [ HostComponent ],
providers: [ providers: [
PrettyPrinter,
CopierService, CopierService,
{ provide: Logger, useClass: TestLogger }, {provide: Logger, useClass: TestLogger }
{ provide: PrettyPrinter, useClass: MockPrettyPrinter },
] ]
}).compileComponents();
}); });
// Must be async because
// CodeComponent creates PrettyPrintService which async loads `prettify.js`.
// If not async, `afterAll` finishes before tests do!
beforeEach(async(() => {
fixture = TestBed.createComponent(HostComponent); fixture = TestBed.createComponent(HostComponent);
hostComponent = fixture.componentInstance; hostComponent = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); }));
describe('pretty printing', () => { describe('pretty printing', () => {
const getFormattedCode = () => fixture.nativeElement.querySelector('code').innerHTML; const untilCodeFormatted = () => {
const emitter = hostComponent.codeComponent.codeFormatted;
return emitter.pipe(first()).toPromise();
};
const hasLineNumbers = async () => {
// presence of `<li>`s are a tell-tale for line numbers
await untilCodeFormatted();
return 0 < fixture.nativeElement.querySelectorAll('li').length;
};
it('should format a one-line code sample without linenums by default', () => { it('should format a one-line code sample', async () => {
hostComponent.setCode(oneLineCode); hostComponent.setCode(oneLineCode);
expect(getFormattedCode()).toBe( await untilCodeFormatted();
`Formatted code (language: auto, linenums: false): ${oneLineCode}`);
// 'pln' spans are a tell-tale for syntax highlighting
const spans = fixture.nativeElement.querySelectorAll('span.pln');
expect(spans.length).toBeGreaterThan(0, 'formatted spans');
}); });
it('should add line numbers to one-line code sample when linenums is `true`', () => { it('should format a one-line code sample without linenums by default', async () => {
hostComponent.setCode(oneLineCode); hostComponent.setCode(oneLineCode);
hostComponent.linenums = true; expect(await hasLineNumbers()).toBe(false);
fixture.detectChanges();
expect(getFormattedCode()).toBe(
`Formatted code (language: auto, linenums: true): ${oneLineCode}`);
}); });
it('should add line numbers to one-line code sample when linenums is `\'true\'`', () => { it('should add line numbers to one-line code sample when linenums set true', async () => {
hostComponent.setCode(oneLineCode);
hostComponent.linenums = 'true'; hostComponent.linenums = 'true';
fixture.detectChanges(); fixture.detectChanges();
expect(getFormattedCode()).toBe( expect(await hasLineNumbers()).toBe(true);
`Formatted code (language: auto, linenums: true): ${oneLineCode}`);
}); });
it('should format a small multi-line code without linenums by default', async () => { it('should format a small multi-line code without linenums by default', async () => {
hostComponent.setCode(smallMultiLineCode); hostComponent.setCode(smallMultiLineCode);
expect(getFormattedCode()).toBe( expect(await hasLineNumbers()).toBe(false);
`Formatted code (language: auto, linenums: false): ${smallMultiLineCode}`);
}); });
it('should add line numbers to a big multi-line code by default', async () => { it('should add line numbers to a big multi-line code by default', async () => {
hostComponent.setCode(bigMultiLineCode); hostComponent.setCode(bigMultiLineCode);
expect(getFormattedCode()).toBe( expect(await hasLineNumbers()).toBe(true);
`Formatted code (language: auto, linenums: true): ${bigMultiLineCode}`);
}); });
it('should format big multi-line code without linenums when linenums is `false`', async () => { it('should format big multi-line code without linenums when linenums set false', async () => {
hostComponent.setCode(bigMultiLineCode);
hostComponent.linenums = false; hostComponent.linenums = false;
fixture.detectChanges(); fixture.detectChanges();
expect(getFormattedCode()).toBe(
`Formatted code (language: auto, linenums: false): ${bigMultiLineCode}`);
});
it('should format big multi-line code without linenums when linenums is `\'false\'`', async () => {
hostComponent.setCode(bigMultiLineCode); hostComponent.setCode(bigMultiLineCode);
hostComponent.linenums = 'false'; expect(await hasLineNumbers()).toBe(false);
fixture.detectChanges();
expect(getFormattedCode()).toBe(
`Formatted code (language: auto, linenums: false): ${bigMultiLineCode}`);
}); });
}); });
@ -107,16 +117,9 @@ describe('CodeComponent', () => {
hostComponent.linenums = false; hostComponent.linenums = false;
fixture.detectChanges(); fixture.detectChanges();
hostComponent.setCode(` hostComponent.setCode(' abc\n let x = text.split(\'\\n\');\n ghi\n\n jkl\n');
abc
let x = text.split('\\n');
ghi
jkl
`);
const codeContent = fixture.nativeElement.querySelector('code').textContent; const codeContent = fixture.nativeElement.querySelector('code').textContent;
expect(codeContent).toEqual( expect(codeContent).toEqual('abc\n let x = text.split(\'\\n\');\nghi\n\njkl');
'Formatted code (language: auto, linenums: false): abc\n let x = text.split(\'\\n\');\nghi\n\njkl');
}); });
it('should trim whitespace from the code before rendering', () => { it('should trim whitespace from the code before rendering', () => {

View File

@ -47,7 +47,6 @@ describe('DocumentService', () => {
docService.currentDocument.subscribe(); docService.currentDocument.subscribe();
httpMock.expectOne(CONTENT_URL_PREFIX + 'initial/doc.json'); httpMock.expectOne(CONTENT_URL_PREFIX + 'initial/doc.json');
expect().nothing(); // Prevent jasmine from complaining about no expectations.
}); });
it('should emit a document each time the location changes', () => { it('should emit a document each time the location changes', () => {
@ -186,7 +185,6 @@ describe('DocumentService', () => {
docService.currentDocument.subscribe(); docService.currentDocument.subscribe();
httpMock.expectOne(CONTENT_URL_PREFIX + 'index.json'); httpMock.expectOne(CONTENT_URL_PREFIX + 'index.json');
expect().nothing(); // Prevent jasmine from complaining about no expectations.
}); });
it('should map the "folder" locations to the correct document request', () => { it('should map the "folder" locations to the correct document request', () => {
@ -194,7 +192,6 @@ describe('DocumentService', () => {
docService.currentDocument.subscribe(); docService.currentDocument.subscribe();
httpMock.expectOne(CONTENT_URL_PREFIX + 'guide.json'); httpMock.expectOne(CONTENT_URL_PREFIX + 'guide.json');
expect().nothing(); // Prevent jasmine from complaining about no expectations.
}); });
}); });
}); });

View File

@ -4,9 +4,9 @@ import { VersionInfo } from 'app/navigation/navigation.service';
@Component({ @Component({
selector: 'aio-mode-banner', selector: 'aio-mode-banner',
template: ` template: `
<div *ngIf="mode == 'archive'" class="mode-banner alert archive-warning"> <div *ngIf="mode == 'archive'" class="mode-banner">
<p>This is the <strong>archived documentation for Angular v{{version?.major}}.</strong> This is the <strong>archived documentation for Angular v{{version?.major}}.</strong>
Please visit <a href="https://angular.io/">angular.io</a> to see documentation for the current version of Angular.</p> Please visit <a href="https://angular.io/">angular.io</a> to see documentation for the current version of Angular.
</div> </div>
` `
}) })

View File

@ -51,8 +51,6 @@ describe('ScrollService', () => {
spyOn(window, 'scrollBy'); spyOn(window, 'scrollBy');
}); });
afterEach(() => scrollService.ngOnDestroy());
it('should debounce `updateScrollPositonInHistory()`', fakeAsync(() => { it('should debounce `updateScrollPositonInHistory()`', fakeAsync(() => {
const updateScrollPositionInHistorySpy = spyOn(scrollService, 'updateScrollPositionInHistory'); const updateScrollPositionInHistorySpy = spyOn(scrollService, 'updateScrollPositionInHistory');
@ -67,25 +65,6 @@ describe('ScrollService', () => {
expect(updateScrollPositionInHistorySpy).toHaveBeenCalledTimes(1); expect(updateScrollPositionInHistorySpy).toHaveBeenCalledTimes(1);
})); }));
it('should stop updating scroll position once destroyed', fakeAsync(() => {
const updateScrollPositionInHistorySpy = spyOn(scrollService, 'updateScrollPositionInHistory');
window.dispatchEvent(new Event('scroll'));
tick(250);
expect(updateScrollPositionInHistorySpy).toHaveBeenCalledTimes(1);
window.dispatchEvent(new Event('scroll'));
tick(250);
expect(updateScrollPositionInHistorySpy).toHaveBeenCalledTimes(2);
updateScrollPositionInHistorySpy.calls.reset();
scrollService.ngOnDestroy();
window.dispatchEvent(new Event('scroll'));
tick(250);
expect(updateScrollPositionInHistorySpy).not.toHaveBeenCalled();
}));
it('should set `scrollRestoration` to `manual` if supported', () => { it('should set `scrollRestoration` to `manual` if supported', () => {
if (scrollService.supportManualScrollRestoration) { if (scrollService.supportManualScrollRestoration) {
expect(window.history.scrollRestoration).toBe('manual'); expect(window.history.scrollRestoration).toBe('manual');
@ -133,23 +112,6 @@ describe('ScrollService', () => {
expect(scrollService.topOffset).toBe(100 + topMargin); expect(scrollService.topOffset).toBe(100 + topMargin);
expect(document.querySelector).toHaveBeenCalled(); expect(document.querySelector).toHaveBeenCalled();
}); });
it('should stop updating on resize once destroyed', () => {
let clientHeight = 50;
(document.querySelector as jasmine.Spy).and.callFake(() => ({clientHeight}));
expect(scrollService.topOffset).toBe(50 + topMargin);
clientHeight = 100;
window.dispatchEvent(new Event('resize'));
expect(scrollService.topOffset).toBe(100 + topMargin);
scrollService.ngOnDestroy();
clientHeight = 200;
window.dispatchEvent(new Event('resize'));
expect(scrollService.topOffset).toBe(100 + topMargin);
});
}); });
describe('#topOfPageElement', () => { describe('#topOfPageElement', () => {

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