Compare commits

..

78 Commits

Author SHA1 Message Date
d0ccf5f169 release: cut the v6.0.0 release 2018-05-03 12:17:26 -07:00
ecde15298a build: update to rxjs@6.0.0 (#23679)
PR Close #23679
2018-05-03 10:53:39 -07:00
983e5f2d7e fix(aio): correctly route embedded live-example URLs from SW (#23637)
Partially addresses #23626.

PR Close #23637
2018-05-02 15:55:23 -07:00
5fc4299e0a refactor(aio): move right margin from .home image to .home anchor (#23624)
This makes the outline of `.home` symmetric.

PR Close #23624
2018-05-02 15:54:15 -07:00
1823d5dd1c style(aio): add space between .home and .hamburger (#23624)
When the `.hamburger` icon is clicked, it's background is drawn until
the very edge of `.home`'s image, leaving no space.

PR Close #23624
2018-05-02 15:54:15 -07:00
91d4da0d2f docs: add missing link to bootstrapping section (#23214)
PR Close #23214
2018-05-02 15:53:02 -07:00
22eb8e26fc build(aio): align stackblitz files with Angular CLI V6 (#23521)
Also cleans up legacy references to `.angular-cli.json`

PR Close #23521
2018-05-02 15:00:57 -07:00
f6002c1702 docs(forms): Fixed a typo in the reactive form (From 'address' to 'secretLairs') section (#23221)
PR Close #23221
2018-05-02 15:00:28 -07:00
14138f6382 docs(elements): add intro connecting angular elements to custom elements (#23638)
PR Close #23638
2018-05-02 14:57:20 -07:00
f11daa2031 docs(aio): update Egghead.io URL (#23598)
Closes #23597
PR Close #23598
2018-05-01 10:27:16 -07:00
31a435ef5b docs: fix typo in tag name (my-child --> app-child) (#23606)
Fixes #23599

PR Close #23606
2018-05-01 10:26:50 -07:00
3e92b22258 test: add i18n to cli-hello-world integration test (#23527)
PR Close #23527
2018-04-27 11:26:50 -07:00
2e5457c824 docs(aio): update docs error in guide/http (#23567)
Updates documentation to include examples for both req.flush and
req.error in http testing examples.

PR Close #23567
2018-04-27 11:26:27 -07:00
1ab5fba92e build(aio): add support for faster, unoptimized serve (#23569)
When running `yarn start` and `yarn serve-and-sync`, we are usually
more interested in faster re-build times than optimized builds. This was
also the behavior, before upgrading to @angular/cli@6 (fc5af69fb).

This commit introduces a new configuration (`fast`), which is used by
`yarn start` and `yarn serve-and-sync` to restore the faster,
unoptimized builds.
Other commands, such as `ng serve` and `ng e2e`, remain unchanged (using
slower, optimized builds).

PR Close #23569
2018-04-27 11:26:22 -07:00
e1e57ddaa7 docs: correct more typos (#23565)
PR Close #23565
2018-04-27 11:26:17 -07:00
ee7cb48877 docs: correct typos (#23565)
PR Close #23565
2018-04-27 11:26:10 -07:00
a30c57090a docs: correct node.js version and usage (#23565)
PR Close #23565
2018-04-27 11:26:04 -07:00
8a49ec4f27 ci: add Brandon Roberts as an aio approver (#23417)
PR Close #23417
2018-04-27 11:25:59 -07:00
697b6c040c fix(core): avoid eager providers re-initialization (#23559)
Fix a corner case where eager providers were getting constructed twice if the provider was requested before the initialization of the NgModule is complete.

PR Close #23559
2018-04-27 11:25:47 -07:00
4008e36e80 release: cut the v6.0.0-rc.6 release 2018-04-27 10:47:56 -07:00
e47bb52084 Revert "refactor(core): tree-shake application_module providers (#23477)"
This reverts commit ac2b530f4b.

The change is breaking targets in g3 see cl/194336387.
2018-04-27 07:13:56 -07:00
ac2b530f4b refactor(core): tree-shake application_module providers (#23477)
PR Close #23477
2018-04-25 15:54:41 -07:00
64bf6edf00 docs: update glossary architectural terms (#23045)
PR Close #23045
2018-04-25 13:21:52 -07:00
adf6235479 docs: corrected spelling of "ambient". 2018-04-24 15:05:31 -07:00
04c18ac1aa docs: fix typo (#23514)
PR Close #23514
2018-04-24 14:43:34 -07:00
1b26dd8cdb docs(benchpress): fix typo in README (#23471) (#23488)
PR Close #23488
2018-04-24 14:37:03 -07:00
f721b06bde style: format code 2018-04-24 14:36:30 -07:00
0bc8443e12 fix(compiler): avoid a crash in ngc-wrapped. (#23468)
`ng.performCompilation` can return an `undefined` program, which is not handled by ngc-wrapped.

Avoid crashing by checking for the error return and returning the diagnostics.
PR Close #23468
2018-04-24 13:57:04 -07:00
db17231597 ci(aio): fix deploy-to-firebase script (#23470)
Temporary workaround for angular/angular-cli#10398.
The behavior of `yarn build` remains the same, but building for a
specific deployment env (e.g. archive, next) requires
`yarn build-for $deployEnv`.

PR Close #23470
2018-04-24 11:15:35 -07:00
540626a3a6 build(common): mark locales files as side-effect-full (#23509)
Fixes https://github.com/angular/angular-cli/issues/10322
PR Close #23509
2018-04-24 11:14:52 -07:00
391bfcede5 docs(aio): Add UpgradingAngularJS to education resources (#23169)
PR Close #23169
2018-04-23 13:36:48 -07:00
d8de6488dd fix(router): cache route handle if found (#22475)
When asking the route reuse strategy to retrieve a detached route handle, store the
return value in a local variable for further processing instead of asking again later.

resolves #22474

PR Close #22475
2018-04-23 13:35:59 -07:00
151fb66848 ci: add alxhub as owner to a few packages (#23510)
PR Close #23510
2018-04-23 10:08:25 -07:00
02424ff0d0 Revert "style(compiler): fix lint issues (#23480)"
This reverts commit f0925d9705.
2018-04-22 12:21:24 -07:00
f0925d9705 style(compiler): fix lint issues (#23480)
PR Close #23480
2018-04-22 11:55:33 -07:00
212b806eda build: make commit validation accept typical Revert messages (#23480)
fixes #23479

PR Close #23480
2018-04-22 11:49:49 -07:00
b9431e88fb fix(compiler): handle undefined annotation metadata (#23349)
In certain cases seen in production, simplify() can returned
undefined when simplifying decorator metadata. This has proven tricky
to reproduce in an isolated test, but the fix is simple and low-risk:
don't attempt to spread an undefined set of annotations in the first
place.

PR Close #23349
2018-04-19 18:57:22 -07:00
7790cfa0d0 Revert "fix(compiler): Pretty print object instead of [Object object] (#22689)" (#23442)
This reverts commit 8555a3a3cd.

Reverted because of https://github.com/angular/angular/issues/23440

PR Close #23442
2018-04-19 14:52:49 -07:00
41b5149509 docs(aio): add front page campaign for the ng-conf live stream (#23391)
PR Close #23391
2018-04-17 14:13:43 -07:00
06f865640d docs(aio): Cleanup examples with edits from Igor/George (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
824f74f27b build(aio): turn on webpack's stats.json generation for debugging purposes (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
5301c43eed build(aio): add @angular/language-service (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
f280d1aef1 docs(aio): Bump shared yarn.lock file for examples (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
5e741d42a6 docs(aio): Bump shared dependencies to RC5 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
0035d41030 docs(aio): Fix failing upgrade-module tests (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
08f447ceec docs(aio): Fix failing boilerplate tests (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
8953f123e3 docs(aio): Upgrade examples to Angular 6 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
6274007e3b test(aio): fix failing tests (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
ee76be7783 docs(aio): update yarn test command in README.md (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
a8c720bc3a build(aio): update to @angular/material@6.0.0-rc.11 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
ac47a3cd93 test(aio): move reflect-metadata polyfills to test.ts (#23234)
This resolves https://github.com/angular/angular-cli/issues/10333 and nicely cleans up the code.

PR Close #23234
2018-04-17 14:09:04 -07:00
041458a3d2 build(aio): update to angular/core@6.0.0-rc.5 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
2cb74b748f style(aio): lint fixes for examples (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
cb0bfe7a43 test(aio): fix tests and update testing infra (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
8ee11aeaa6 build(aio): update tslint and codelyzer (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
bf89fcb361 build(aio): fix deployment script (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
4f70c5b6f7 build(aio): upgrade @angular/cli to 6.0.0-rc.4 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
ad3ebec2a5 build(aio): upgrade @angular/* to 6.0.0-rc.4 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
3f5d61f2dd build(aio): remove redundant flags from cli commands (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
11ada7f78b build(aio): switch to webpack-cli for IE polyfills (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
0b96bc7456 build(aio): upgrade rxjs to 6.0.0-turbo-rc.4 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
fefadadff3 ci: chown bazel-built packages when running integration tests (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
946057ae29 build: update to rxjs@6.0.0-uncanny-rc.7 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
d4293aaaaa build: remove a postinstall-patch to fix rxjs (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
e3dcc227f6 build(aio): reorder entries in package.json (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
c9230dd90e build: fix angular.json that was missing keys due to cli bugs (#23234)
https://github.com/angular/angular-cli/issues/10225
https://github.com/angular/angular-cli/issues/10226

PR Close #23234
2018-04-17 14:09:04 -07:00
234af9ba59 build(aio): update to @angular/material@6.0.0-rc.1 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
7204028d3e build(aio): update to @angular/material@5.2.4 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
f7c55952bf build: update to rxjs@6.0.0-tactical-rc.1 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
e38e3bd135 test: simplify config for cli-hello-world (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
cd20c01ba1 test: update cli-hello-world to cli@6.0.0-rc.2 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
12a191ef3f build(aio): update to @angular/cli@6.0.0-rc.2 + project layout update (#23234)
project layout was updated using:
yarn ng update @angular/cli --migrate-only --from=1.7.3

PR Close #23234
2018-04-17 14:09:04 -07:00
65e67b3c3a build(aio): upgrade to @angular/*@6.0.0-rc.3 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
32e57f6197 build(aio): upgrade to @angular/*@6.0.0-rc.2 (#23234)
PR Close #23234
2018-04-17 14:09:04 -07:00
7de69ba29b ci(aio): fix aio-monitoring tests (#23390)
Previously, we were running the e2e tests from master against
`https://angular.io` (deployed from the stable branch). Often the e2e
tests from master do not apply to the stable branch, since the app has
deviated slightly.

This commit fixes this by stop running the full e2e tests against the
deployed versions, but a smaller set of "smoke tests", which check basic
functionality that is less likely to change between versions.

PR Close #23390
2018-04-17 13:45:38 -07:00
44193c0b94 refactor(aio): rename directory (tests/deployment-config --> tests/deployment) (#23390)
PR Close #23390
2018-04-17 13:45:38 -07:00
6db8241ffa refactor(aio): rename spec file (#23390)
PR Close #23390
2018-04-17 13:45:38 -07:00
33c594516c refactor(aio): rename yarn script (deployment-config-test --> redirects-test) (#23390)
PR Close #23390
2018-04-17 13:45:38 -07:00
1424 changed files with 24729 additions and 71322 deletions

View File

@ -1,19 +0,0 @@
# Encryption
Based on https://github.com/circleci/encrypted-files
In the CircleCI web UI, we have a secret variable called `KEY`
https://circleci.com/gh/angular/angular/edit#env-vars
which is only exposed to non-fork builds
(see "Pass secrets to builds from forked pull requests" under
https://circleci.com/gh/angular/angular/edit#advanced-settings)
We use this as a symmetric AES encryption key to encrypt tokens like
a GitHub token that enables publishing snapshots.
To create the github_token file, we take this approach:
- Find the angular-builds:token in http://valentine
- Go inside the ngcontainer docker image so you use the same version of openssl as we will at runtime: `docker run --rm -it angular/ngcontainer`
- echo "https://[token]:@github.com" > credentials
- openssl aes-256-cbc -e -in credentials -out .circleci/github_token -k $KEY
- If needed, base64-encode the result so you can copy-paste it out of docker: `base64 github_token`

View File

@ -3,10 +3,7 @@
# See remote cache documentation in /docs/BAZEL.md
# Don't be spammy in the logs
# TODO(gmagolan): Hide progress again once build performance improves
# Presently, CircleCI can timeout during bazel test ... with the following
# error: Too long with no output (exceeded 10m0s)
# build --noshow_progress
build --noshow_progress
# Don't run manual tests
test --test_tag_filters=-manual

View File

@ -12,8 +12,8 @@
## IMPORTANT
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file.
var_1: &docker_image angular/ngcontainer:0.3.3
var_2: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.3.3
var_1: &docker_image angular/ngcontainer:0.2.0
var_2: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.2.0
# Define common ENV vars
var_3: &define_env_vars
@ -63,7 +63,7 @@ jobs:
- run: yarn install --frozen-lockfile --non-interactive
- run: ./node_modules/.bin/gulp lint
test:
build:
<<: *job_defaults
resource_class: xlarge
steps:
@ -80,152 +80,37 @@ jobs:
- run: ls /home/circleci/bazel_repository_cache || true
- run: bazel info release
- run: bazel run @nodejs//:yarn
- run: bazel run @yarn//:yarn
# Use bazel query so that we explicitly ask for all buildable targets to be built as well
# This avoids waiting for the slowest build target to finish before running the first test
# See https://github.com/bazelbuild/bazel/issues/4257
# NOTE: Angular developers should typically just bazel build //packages/... or bazel test //packages/...
- run: bazel query --output=label //... | xargs bazel test --build_tag_filters=-ivy-only --test_tag_filters=-manual,-ivy-only
- run: bazel query --output=label //... | xargs bazel test
# We run the integration tests outside of Bazel for now.
# See comments inside this script.
- run: xvfb-run --auto-servernum ./integration/run_tests.sh
# CircleCI will allow us to go back and view/download these artifacts from past builds.
# Also we can use a service like https://buildsize.org/ to automatically track binary size of these artifacts.
# The destination keys need be format {projectName}/{context}/{fileName} so that the github-robot can process them for size calculations
# projectName should remain consistant to group files
# context and fileName can be almost anything (within usual URI rules)
# There should only be exactly 2 forward slashes in the path
# This is so they're backwards compatiable with the existing data we have on bundle sizes
- store_artifacts:
path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js
destination: core/hello_world/bundle
destination: packages/core/test/bundling/hello_world/bundle.min.js
- store_artifacts:
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js
destination: core/todo/bundle
destination: packages/core/test/bundling/todo/bundle.min.js
- store_artifacts:
path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js.br
destination: core/hello_world/bundle.br
path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js.brotli
destination: packages/core/test/bundling/hello_world/bundle.min.js.brotli
- store_artifacts:
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.br
destination: core/todo/bundle.br
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.brotli
destination: packages/core/test/bundling/todo/bundle.min.js.brotli
- save_cache:
key: *cache_key
paths:
- "node_modules"
- "~/bazel_repository_cache"
# Temporary job to test what will happen when we flip the Ivy flag to true
test_ivy_jit:
<<: *job_defaults
resource_class: xlarge
steps:
- *define_env_vars
- checkout:
<<: *post_checkout
# See remote cache documentation in /docs/BAZEL.md
- run: .circleci/setup_cache.sh
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
- *setup-bazel-remote-cache
- restore_cache:
key: *cache_key
- run: bazel run @yarn//:yarn
- run: bazel query --output=label //... | xargs bazel test --define=compile=jit --build_tag_filters=ivy-jit --test_tag_filters=-manual,ivy-jit
test_ivy_aot:
<<: *job_defaults
resource_class: xlarge
steps:
- *define_env_vars
- checkout:
<<: *post_checkout
# See remote cache documentation in /docs/BAZEL.md
- run: .circleci/setup_cache.sh
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
- *setup-bazel-remote-cache
- restore_cache:
key: *cache_key
- run: bazel run @yarn//:yarn
- run: bazel query --output=label //... | xargs bazel test --define=compile=local --build_tag_filters=ivy-local --test_tag_filters=-manual,ivy-local
# This job exists only for backwards-compatibility with old scripts and tests
# that rely on the pre-Bazel dist/packages-dist layout.
# It duplicates some work with the job above: we build the bazel packages
# twice. Even though we have a remote cache, these jobs will typically run in
# parallel so up-to-date outputs will not be available at the time the build
# starts.
# No new jobs should depend on this one.
build-packages-dist:
<<: *job_defaults
resource_class: xlarge
steps:
- *define_env_vars
- checkout:
<<: *post_checkout
# See remote cache documentation in /docs/BAZEL.md
- run: .circleci/setup_cache.sh
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
- *setup-bazel-remote-cache
- run: bazel run @nodejs//:yarn
- run: scripts/build-packages-dist.sh
# Save the npm packages from //packages/... for other workflow jobs to read
# https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs
- persist_to_workspace:
root: dist
paths:
- packages-dist
- packages-dist-ivy-jit
- packages-dist-ivy-local
# We run the integration tests outside of Bazel for now.
# They are a separate workflow job so that they can be easily re-run.
# When the tests are ported to bazel test targets, they should move to the "test"
# job above, as part of the bazel test command. That has flaky_test_attempts so the
# need to re-run manually should be alleviated.
# See comments inside the integration/run_tests.sh script.
integration_test:
<<: *job_defaults
# Note: we run Bazel in one of the integration tests, and it can consume >2G
# of memory. Together with the system under test, this can exhaust the RAM
# on a 4G worker so we use a larger machine here too.
resource_class: xlarge
steps:
- *define_env_vars
- checkout:
<<: *post_checkout
- attach_workspace:
at: dist
- run: xvfb-run --auto-servernum ./integration/run_tests.sh
# This job updates the content of repos like github.com/angular/core-builds
# for every green build on angular/angular.
publish_snapshot:
<<: *job_defaults
steps:
# See below - ideally this job should not trigger for non-upstream builds.
# But since it does, we have to check this condition.
- run:
name: Skip this job for Pull Requests and Fork builds
# Note, `|| true` on the end makes this step always exit 0
command: '[[
-v CIRCLE_PR_NUMBER
|| "$CIRCLE_PROJECT_USERNAME" != "angular"
|| "$CIRCLE_PROJECT_REPONAME" != "angular"
]] && circleci step halt || true'
- checkout:
<<: *post_checkout
- attach_workspace:
at: dist
# CircleCI has a config setting to force SSH for all github connections
# This is not compatible with our mechanism of using a Personal Access Token
# Clear the global setting
- run: git config --global --unset "url.ssh://git@github.com.insteadof"
- run:
name: Decrypt github credentials
command: 'openssl aes-256-cbc -d -in .circleci/github_token -k "${KEY}" -out ~/.git_credentials'
- run: ./scripts/ci/publish-build-artifacts.sh
aio_monitoring:
<<: *job_defaults
@ -241,28 +126,7 @@ workflows:
default_workflow:
jobs:
- lint
- test
- test_ivy_jit
- test_ivy_aot
- build-packages-dist
- integration_test:
requires:
- build-packages-dist
- publish_snapshot:
# Note: no filters on this job because we want it to run for all upstream branches
# We'd really like to filter out pull requests here, but not yet available:
# https://discuss.circleci.com/t/workflows-pull-request-filter/14396/4
# Instead, the job just exits immediately at the first step.
requires:
# Only publish if tests and integration tests pass
- test
- test_ivy_jit
- test_ivy_aot
- integration_test
# Get the artifacts to publish from the build-packages-dist job
# since the publishing script expects the legacy outputs layout.
- build-packages-dist
- build
aio_monitoring:
jobs:
- aio_monitoring

Binary file not shown.

View File

@ -1,14 +1,5 @@
# Configuration for angular-robot
#options for the size plugin
size:
disabled: false
maxSizeIncrease: 1000
circleCiStatusName: "ci/circleci: build-packages-dist"
status:
disabled: false
context: "ci/angular: size"
# options for the merge plugin
merge:
# the status will be added to your pull requests
@ -45,12 +36,10 @@ merge:
- "packages/language-service/**"
- "**/.gitignore"
- "**/.gitkeep"
- "**/package.json"
- "**/tsconfig-build.json"
- "**/tsconfig.json"
- "**/rollup.config.js"
- "**/BUILD.bazel"
- "packages/**/integrationtest/**"
- "packages/**/test/**"
# comment that will be added to a PR when there is a conflict, leave empty or set to false to disable

View File

@ -8,22 +8,22 @@
# alexeagle - Alex Eagle
# alxhub - Alex Rickabaugh
# andrewseguin - Andrew Seguin
# benlesh - Ben Lesh
# brandonroberts - Brandon Roberts
# brocco - Mike Brocchi
# chuckjaz - Chuck Jazdzewski
# filipesilva - Filipe Silva
# gkalpak - George Kalpakas
# hansl - Hans Larsen
# IgorMinar - Igor Minar
# jasonaden - Jason Aden
# jenniferfell - Jennifer Fell
# kapunahelewong - Kapunahele Wong
# kara - Kara Erickson
# kyliau - Keen Yee Liau
# matsko - Matias Niemelä
# mhevery - Misko Hevery
# petebacondarwin - Pete Bacon Darwin
# pkozlowski-opensource - Pawel Kozlowski
# robwormald - Rob Wormald
# tinayuangao - Tina Gao
# vicb - Victor Berchet
# vikerman - Vikram Subramanian
@ -92,10 +92,9 @@ groups:
- "*.bzl"
- "packages/bazel/*"
- "tools/bazel.rc"
- "/docs/BAZEL.md"
users:
- alexeagle #primary
- kyliau
- chuckjaz
- IgorMinar #fallback
- mhevery
- vikerman #fallback
@ -132,113 +131,42 @@ groups:
conditions:
files:
- "packages/core/*"
- "aio/content/guide/bootstrapping.md"
- "aio/content/examples/bootstrapping/*"
- "aio/content/guide/attribute-directives.md"
- "aio/content/examples/attribute-directives/*"
- "aio/content/images/guide/attribute-directives/*"
- "aio/content/guide/structural-directives.md"
- "aio/content/examples/structural-directives/*"
- "aio/content/images/guide/structural-directives/*"
- "aio/content/guide/dynamic-component-loader.md"
- "aio/content/examples/dynamic-component-loader/*"
- "aio/content/images/guide/dynamic-component-loader/*"
- "aio/content/guide/template-syntax.md"
- "aio/content/examples/template-syntax/*"
- "aio/content/images/guide/template-syntax/*"
- "aio/content/guide/dependency-injection.md"
- "aio/content/examples/dependency-injection/*"
- "aio/content/images/guide/dependency-injection/*"
- "aio/content/guide/dependency-injection-in-action.md"
- "aio/content/examples/dependency-injection-in-action/*"
- "aio/content/images/guide/dependency-injection-in-action/*"
- "aio/content/guide/hierarchical-dependency-injection.md"
- "aio/content/examples/hierarchical-dependency-injection/*"
- "aio/content/guide/singleton-services.md"
- "aio/content/guide/dependency-injection-pattern.md"
- "aio/content/guide/providers.md"
- "aio/content/examples/providers/*"
- "aio/content/guide/component-interaction.md"
- "aio/content/examples/component-interaction/*"
- "aio/content/images/guide/component-interaction/*"
- "aio/content/guide/component-styles.md"
- "aio/content/examples/component-styles/*"
- "aio/content/guide/lifecycle-hooks.md"
- "aio/content/examples/lifecycle-hooks/*"
- "aio/content/images/guide/lifecycle-hooks/*"
- "aio/content/examples/ngcontainer/*"
- "aio/content/images/guide/ngcontainer/*"
- "aio/content/guide/pipes.md"
- "aio/content/examples/pipes/*"
- "aio/content/images/guide/pipes/*"
- "aio/content/guide/entry-components.md"
- "aio/content/guide/set-document-title.md"
- "aio/content/examples/set-document-title/*"
- "aio/content/images/guide/set-document-title/*"
- "aio/content/guide/ngmodules.md"
- "aio/content/examples/ngmodules/*"
- "aio/content/examples/ngmodule/*"
- "aio/content/images/guide/ngmodule/*"
- "aio/content/guide/ngmodule-faq.md"
- "aio/content/examples/ngmodule-faq/*"
- "aio/content/guide/module-types.md"
- "aio/content/guide/sharing-ngmodules.md"
- "aio/content/guide/frequent-ngmodules.md"
- "aio/content/images/guide/frequent-ngmodules/*"
- "aio/content/guide/ngmodule-api.md"
- "aio/content/guide/ngmodule-vs-jsmodule.md"
- "aio/content/guide/feature-modules.md"
- "aio/content/examples/feature-modules/*"
- "aio/content/images/guide/feature-modules/*"
- "aio/content/guide/lazy-loading-ngmodules.md"
- "aio/content/examples/lazy-loading-ngmodules/*"
- "aio/content/images/guide/lazy-loading-ngmodules"
users:
- mhevery #primary
- jasonaden
- chuckjaz
- kara
- vicb
- IgorMinar
- jenniferfell #docs only
- IgorMinar #fallback
animations:
conditions:
files:
- "packages/animations/*"
- "packages/platform-browser/animations/*"
- "aio/content/guide/animations.md"
- "aio/content/examples/animations/*"
- "aio/content/images/guide/animations/*"
users:
- matsko #primary
- mhevery #fallback
- IgorMinar #fallback
- jenniferfell #docs only
compiler/i18n:
conditions:
files:
- "packages/compiler/src/i18n/*"
- "aio/content/guide/i18n.md"
- "aio/content/examples/i18n/*"
users:
- vicb #primary
- alxhub
- IgorMinar #fallback
- mhevery #fallback
- jenniferfell #docs only
compiler:
conditions:
files:
- "packages/compiler/*"
- "aio/content/guide/aot-compiler.md"
users:
- alxhub #primary
- chuckjaz #primary
- vicb
- mhevery
- IgorMinar #fallback
- jenniferfell #docs only
compiler-cli/ngtools:
conditions:
@ -247,6 +175,7 @@ groups:
users:
- hansl
- filipesilva #fallback
- brocco #fallback
- IgorMinar #fallback
compiler-cli:
@ -282,97 +211,57 @@ groups:
files:
- "packages/forms/*"
- "aio/content/guide/forms.md"
- "aio/content/examples/forms/*"
- "aio/content/images/guide/forms/*"
- "aio/content/guide/form-validation.md"
- "aio/content/examples/form-validation/*"
- "aio/content/images/guide/form-validation/*"
- "aio/content/guide/dynamic-form.md"
- "aio/content/examples/dynamic-form/*"
- "aio/content/images/guide/dynamic-form/*"
- "aio/content/guide/reactive-forms.md"
- "aio/content/examples/forms/*"
- "aio/content/examples/form-validation/*"
- "aio/content/examples/reactive-forms/*"
- "aio/content/images/guide/reactive-forms/*"
users:
- kara #primary
- tinayuangao #secondary
- IgorMinar #fallback
- mhevery #fallback
- jenniferfell #docs only
http:
conditions:
files:
- "packages/common/http/*"
- "packages/http/*"
- "aio/content/guide/http.md"
- "aio/content/examples/http/*"
- "aio/content/images/guide/http/*"
users:
- alxhub #primary
- IgorMinar
- mhevery #fallback
- jenniferfell #docs only
language-service:
conditions:
files:
- "packages/language-service/*"
- "aio/content/guide/language-service.md"
- "aio/content/images/guide/language-service/*"
users:
- kyliau #primary
- chuckjaz #primary
# needs secondary
- vicb
- IgorMinar #fallback
- mhevery #fallback
- jenniferfell #docs only
router:
conditions:
files:
- "packages/router/*"
- "aio/content/guide/router.md"
- "aio/content/examples/router/*"
- "aio/content/images/guide/router/*"
users:
- jasonaden #primary
- vicb
- IgorMinar #fallback
- mhevery #fallback
- jenniferfell #docs only
testing:
conditions:
files:
- "*/testing/*"
- "aio/content/guide/testing.md"
- "aio/content/examples/testing/*"
- "aio/content/images/guide/testing/*"
users:
- vikerman
- IgorMinar #fallback
- mhevery #fallback
- jenniferfell #docs only
upgrade:
conditions:
files:
- "packages/upgrade/*"
- "aio/content/guide/upgrade.md"
- "aio/content/examples/upgrade-module/*"
- "aio/content/images/guide/upgrade/*"
- "aio/content/examples/upgrade-phonecat-1-typescript/*"
- "aio/content/examples/upgrade-phonecat-2-hybrid/*"
- "aio/content/examples/upgrade-phonecat-3-final/*"
- "aio/content/guide/upgrade-performance.md"
- "aio/content/guide/ajs-quick-reference.md"
- "aio/content/examples/ajs-quick-reference/*"
users:
- petebacondarwin #primary
- gkalpak
- IgorMinar #fallback
- mhevery #fallback
- jenniferfell #docs only
platform-browser:
conditions:
@ -388,15 +277,12 @@ groups:
conditions:
files:
- "packages/platform-server/*"
- "aio/content/guide/universal.md"
- "aio/content/examples/universal/*"
users:
- vikerman #primary
- alxhub #secondary
- vicb
- IgorMinar #fallback
- mhevery #fallback
- jenniferfell #docs only
platform-webworker:
conditions:
@ -412,34 +298,22 @@ groups:
conditions:
files:
- "packages/service-worker/*"
- "aio/content/guide/service-worker-getting-started.md"
- "aio/content/examples/service-worker-getting-started/*"
- "aio/content/guide/service-worker-communications.md"
- "aio/content/guide/service-worker-config.md"
- "aio/content/guide/service-worker-devops.md"
- "aio/content/guide/service-worker-intro.md"
- "aio/content/images/guide/service-worker/*"
users:
- gkalpak #primary
- alxhub
- IgorMinar
- alxhub #primary
- gkalpak
- IgorMinar #fallback
- mhevery #fallback
- jenniferfell #docs only
elements:
conditions:
files:
- "packages/elements/*"
- "aio/content/examples/elements/*"
- "aio/content/images/guide/elements/*"
- "aio/content/guide/elements.md"
users:
- andrewseguin #primary
- gkalpak
- robwormald
- IgorMinar #fallback
- mhevery #fallback
- jenniferfell #docs only
benchpress:
conditions:
@ -451,7 +325,7 @@ groups:
- IgorMinar #fallback
- mhevery #fallback
docs-infra:
angular.io:
conditions:
files:
include:
@ -464,7 +338,7 @@ groups:
- gkalpak
- mhevery #fallback
docs/guide-and-tutorial:
angular.io-guide-and-tutorial:
conditions:
files:
include:
@ -474,20 +348,19 @@ groups:
- "aio/content/navigation.json"
- "aio/content/license.md"
users:
- kapunahelewong
- stephenfluin
- jenniferfell
- brandonroberts
- petebacondarwin
- gkalpak
- IgorMinar
- brandonroberts
- mhevery #fallback
docs/marketing:
angular.io-marketing:
conditions:
files:
include:
- "aio/content/marketing/*"
- "aio/content/images/marketing/*"
- "aio/content/navigation.json"
- "aio/content/license.md"
users:
@ -497,43 +370,3 @@ groups:
- IgorMinar
- robwormald
- mhevery #fallback
docs/observables:
conditions:
files:
- "aio/content/examples/observables/*"
- "aio/content/images/guide/observables/*"
- "aio/content/guide/observables.md"
- "aio/content/guide/comparing-observables.md"
- "aio/content/examples/observables-in-angular/*"
- "aio/content/images/guide/observables-in-angular/*"
- "aio/content/guide/observables-in-angular.md"
- "aio/content/examples/practical-observable-usage/*"
- "aio/content/guide/practical-observable-usage.md"
- "aio/content/examples/rx-library/*"
- "aio/content/guide/rx-library.md"
users:
- jasonaden
- benlesh
- IgorMinar
- mhevery
- jenniferfell #docs only
docs/packaging:
conditions:
files:
- "aio/content/guide/npm-packages.md"
- "aio/content/guide/browser-support.md"
- "aio/content/guide/typescript-configuration.md"
- "aio/content/guide/setup-systemjs-anatomy.md"
- "aio/content/examples/setup/*"
- "aio/content/guide/setup.md"
- "aio/content/guide/deployment.md"
- "aio/content/guide/releases.md"
- "aio/content/guide/updating.md"
users:
- IgorMinar #primary
- alexeagle
- hansl
- mhevery #fallback
- jenniferfell #docs only

View File

@ -5,41 +5,53 @@ load("@build_bazel_rules_nodejs//:defs.bzl", "node_modules_filegroup")
exports_files([
"tsconfig.json",
"LICENSE",
"protractor-perf.conf.js",
])
# Developers should always run `bazel run :install`
# This ensures that package.json in subdirectories get installed as well.
alias(
name = "install",
actual = "@nodejs//:yarn",
actual = "@yarn//:yarn",
)
alias(
node_modules_filegroup(
name = "node_modules",
actual = "@angular_deps//:node_modules",
packages = [
"bytebuffer",
"hammerjs",
"jasmine",
"minimist",
"protobufjs",
"reflect-metadata",
"source-map-support",
"tsickle",
"tslib",
"tsutils",
"typescript",
"zone.js",
"@angular-devkit/core",
"@angular-devkit/schematics",
"@types",
"@webcomponents/custom-elements",
],
)
filegroup(
name = "web_test_bootstrap_scripts",
# do not sort
srcs = [
"@angular_deps//:node_modules/reflect-metadata/Reflect.js",
"@angular_deps//:node_modules/zone.js/dist/zone.js",
"@angular_deps//:node_modules/zone.js/dist/zone-testing.js",
"@angular_deps//:node_modules/zone.js/dist/task-tracking.js",
"//:test-events.js",
"//:node_modules/reflect-metadata/Reflect.js",
"//:node_modules/zone.js/dist/zone.js",
"//:node_modules/zone.js/dist/zone-testing.js",
"//:node_modules/zone.js/dist/task-tracking.js",
],
)
filegroup(
name = "angularjs_scripts",
name = "angularjs",
# do not sort
srcs = [
"@angular_deps//:node_modules/angular-1.5/angular.js",
"@angular_deps//:node_modules/angular-1.6/angular.js",
"@angular_deps//:node_modules/angular-mocks-1.5/angular-mocks.js",
"@angular_deps//:node_modules/angular-mocks-1.6/angular-mocks.js",
"@angular_deps//:node_modules/angular-mocks/angular-mocks.js",
"@angular_deps//:node_modules/angular/angular.js",
"//:node_modules/angular/angular.js",
"//:node_modules/angular-mocks/angular-mocks.js",
],
)

View File

@ -1,271 +1,5 @@
<a name="7.0.0-beta.1"></a>
# [7.0.0-beta.1](https://github.com/angular/angular/compare/7.0.0-beta.0...7.0.0-beta.1) (2018-08-08)
### Bug Fixes
* **compiler-cli:** use the oldProgram option in watch mode ([#21364](https://github.com/angular/angular/issues/21364)) ([c6e5b97](https://github.com/angular/angular/commit/c6e5b97)), closes [#21361](https://github.com/angular/angular/issues/21361)
* **core:** In Testability.whenStable update callback, pass more complete ([#25010](https://github.com/angular/angular/issues/25010)) ([16c03c0](https://github.com/angular/angular/commit/16c03c0))
* add mappings for ngfactory & ngsummary files to their module names in aot summary resolver ([#25335](https://github.com/angular/angular/issues/25335)) ([02e201a](https://github.com/angular/angular/commit/02e201a))
* **router:** take base uri into account in `setUpLocationSync()` ([#20244](https://github.com/angular/angular/issues/20244)) ([ba1e25f](https://github.com/angular/angular/commit/ba1e25f)), closes [#20061](https://github.com/angular/angular/issues/20061)
### Features
* **core:** add DoBootstrap interface. ([#24558](https://github.com/angular/angular/issues/24558)) ([732026c](https://github.com/angular/angular/commit/732026c)), closes [#24557](https://github.com/angular/angular/issues/24557)
<a name="6.1.2"></a>
## [6.1.2](https://github.com/angular/angular/compare/6.1.1...6.1.2) (2018-08-08)
### Bug Fixes
* **router:** take base uri into account in `setUpLocationSync()` ([#20244](https://github.com/angular/angular/issues/20244)) ([ae9b4e6](https://github.com/angular/angular/commit/ae9b4e6)), closes [#20061](https://github.com/angular/angular/issues/20061)
* add mappings for ngfactory & ngsummary files to their module names in aot summary resolver ([#25335](https://github.com/angular/angular/issues/25335)) ([054fbbe](https://github.com/angular/angular/commit/054fbbe))
<a name="7.0.0-beta.0"></a>
# [7.0.0-beta.0](https://github.com/angular/angular/compare/6.1.0...7.0.0-beta.0) (2018-08-02)
### Bug Fixes
* **bazel:** allow compile_strategy to be (privately) imported ([#25080](https://github.com/angular/angular/issues/25080)) ([0d1d589](https://github.com/angular/angular/commit/0d1d589))
* **compiler:** update compiler to flatten nested template fns ([#24943](https://github.com/angular/angular/issues/24943)) ([fe14f18](https://github.com/angular/angular/commit/fe14f18))
* **compiler-cli:** correct realPath to realpath. ([#25023](https://github.com/angular/angular/issues/25023)) ([01e6dab](https://github.com/angular/angular/commit/01e6dab))
* **core:** throw error message when @Output not initialized ([#19116](https://github.com/angular/angular/issues/19116)) ([adf510f](https://github.com/angular/angular/commit/adf510f)), closes [#3664](https://github.com/angular/angular/issues/3664)
### Features
* **compiler:** add "original" placeholder value on extracted XMB ([#25079](https://github.com/angular/angular/issues/25079)) ([e99d860](https://github.com/angular/angular/commit/e99d860))
<a name="6.1.1"></a>
## [6.1.1](https://github.com/angular/angular/compare/6.1.0...6.1.1) (2018-08-02)
* **compiler-cli:** correct tsickle dependency version to fix typescript 2.9 compatibility ([fec29fa](https://github.com/angular/angular/commit/317c7087c56b72aa74cd6d6a8f719e6e7fec29fa))
<a name="6.1.0"></a>
# [6.1.0](https://github.com/angular/angular/compare/6.0.0-rc.5...6.1.0) (2018-07-25)
### Bug Fixes
* **animations:** always render end-state styles for orphaned DOM nodes ([#24236](https://github.com/angular/angular/issues/24236)) ([dc4a3d0](https://github.com/angular/angular/commit/dc4a3d0))
* **animations:** set animations styles properly on platform-server ([#24624](https://github.com/angular/angular/issues/24624)) ([0b356d4](https://github.com/angular/angular/commit/0b356d4))
* **animations:** do not throw errors when a destroyed component is animated ([#23836](https://github.com/angular/angular/issues/23836)) ([d2a8687](https://github.com/angular/angular/commit/d2a8687))
* **animations:** Fix browser detection logic ([#24188](https://github.com/angular/angular/issues/24188)) ([b492b9e](https://github.com/angular/angular/commit/b492b9e))
* **animations:** properly clean up queried element styles in safari/edge ([#23633](https://github.com/angular/angular/issues/23633)) ([da9ff25](https://github.com/angular/angular/commit/da9ff25))
* **animations:** retain state styling for nodes that are moved around ([#23534](https://github.com/angular/angular/issues/23534)) ([65211f4](https://github.com/angular/angular/commit/65211f4))
* **animations:** retain trigger-state for nodes that are moved around ([#24238](https://github.com/angular/angular/issues/24238)) ([8db928d](https://github.com/angular/angular/commit/8db928d))
* **bazel:** Allow ng_module to depend on targets w no deps ([#24446](https://github.com/angular/angular/issues/24446)) ([282d351](https://github.com/angular/angular/commit/282d351))
* **benchpress:** Fix promise chain in chrome_driver_extension. ([#23458](https://github.com/angular/angular/issues/23458)) ([d4b6c41](https://github.com/angular/angular/commit/d4b6c41))
* **common:** do not round factional seconds ([#24831](https://github.com/angular/angular/issues/24831)) ([a527c69](https://github.com/angular/angular/commit/a527c69)), closes [#24384](https://github.com/angular/angular/issues/24384)
* **common:** format fractional seconds ([#24844](https://github.com/angular/angular/issues/24844)) ([0b4d85e](https://github.com/angular/angular/commit/0b4d85e)), closes [#24831](https://github.com/angular/angular/issues/24831)
* **common:** properly update collection reference in NgForOf ([#24684](https://github.com/angular/angular/issues/24684)) ([ff84c5c](https://github.com/angular/angular/commit/ff84c5c)), closes [#24155](https://github.com/angular/angular/issues/24155)
* **common:** use correct currency format for locale de-AT ([#24658](https://github.com/angular/angular/issues/24658)) ([dcabb05](https://github.com/angular/angular/commit/dcabb05)), closes [#24609](https://github.com/angular/angular/issues/24609)
* **common:** use correct ICU plural for locale mk ([#24659](https://github.com/angular/angular/issues/24659)) ([64a8584](https://github.com/angular/angular/commit/64a8584))
* **compiler:** fix a few non-tree-shakeable code patterns ([#24677](https://github.com/angular/angular/issues/24677)) ([50d4a4f](https://github.com/angular/angular/commit/50d4a4f))
* **compiler:** i18n_extractor now outputs the correct source file name ([#24885](https://github.com/angular/angular/issues/24885)) ([c8ad965](https://github.com/angular/angular/commit/c8ad965)), closes [#24884](https://github.com/angular/angular/issues/24884)
* **compiler:** support `.` in import statements. ([#20634](https://github.com/angular/angular/issues/20634)) ([d8f7b29](https://github.com/angular/angular/commit/d8f7b29)), closes [#20363](https://github.com/angular/angular/issues/20363)
* **compiler:** avoid a crash in ngc-wrapped. ([#23468](https://github.com/angular/angular/issues/23468)) ([e1c4930](https://github.com/angular/angular/commit/e1c4930))
* **compiler:** generate constant array for i18n attributes ([#23837](https://github.com/angular/angular/issues/23837)) ([cfde36d](https://github.com/angular/angular/commit/cfde36d))
* **compiler:** generate core-compliant hostBindings property ([#24087](https://github.com/angular/angular/issues/24087)) ([01b5acd](https://github.com/angular/angular/commit/01b5acd)), closes [#24013](https://github.com/angular/angular/issues/24013)
* **compiler:** handle undefined annotation metadata ([#23349](https://github.com/angular/angular/issues/23349)) ([ca776c5](https://github.com/angular/angular/commit/ca776c5))
* **compiler-cli:** Use typescript to resolve modules for metadata ([#22856](https://github.com/angular/angular/issues/22856)) ([0d5f2d3](https://github.com/angular/angular/commit/0d5f2d3))
* **compiler-cli:** don't rely on incompatible TS method ([#23550](https://github.com/angular/angular/issues/23550)) ([b1f040f](https://github.com/angular/angular/commit/b1f040f))
* **core:** stop reusing provider definitions across NgModuleRef instances ([#25022](https://github.com/angular/angular/issues/25022)) ([6b859da](https://github.com/angular/angular/commit/6b859da)), closes [#25018](https://github.com/angular/angular/issues/25018)
* **core:** mark NgModule as not the root if APP_ROOT is set to false ([#24814](https://github.com/angular/angular/issues/24814)) ([1089261](https://github.com/angular/angular/commit/1089261))
* **core:** use addCustomEqualityTester instead of overriding toEqual ([#22983](https://github.com/angular/angular/issues/22983)) ([0922228](https://github.com/angular/angular/commit/0922228)), closes [#22939](https://github.com/angular/angular/issues/22939)
* **core:** Injector correctly honors the @Self flag ([#24520](https://github.com/angular/angular/issues/24520)) ([ccbda9d](https://github.com/angular/angular/commit/ccbda9d))
* **core:** avoid eager providers re-initialization ([#23559](https://github.com/angular/angular/issues/23559)) ([0c6dc45](https://github.com/angular/angular/commit/0c6dc45))
* **core:** call ngOnDestroy on all services that have it ([#23755](https://github.com/angular/angular/issues/23755)) ([fc03427](https://github.com/angular/angular/commit/fc03427)), closes [#22466](https://github.com/angular/angular/issues/22466) [#22240](https://github.com/angular/angular/issues/22240) [#14818](https://github.com/angular/angular/issues/14818)
* **docs-infra:** fix table header layout in API pages ([#24919](https://github.com/angular/angular/issues/24919)) ([3cd9645](https://github.com/angular/angular/commit/3cd9645))
* **elements:** always check to create strategy ([#23825](https://github.com/angular/angular/issues/23825)) ([b1cda36](https://github.com/angular/angular/commit/b1cda36))
* **elements:** prevent closure renaming of platform properties ([#23843](https://github.com/angular/angular/issues/23843)) ([d4b8b24](https://github.com/angular/angular/commit/d4b8b24))
* **forms:** properly handle special properties in FormGroup.get ([#22249](https://github.com/angular/angular/issues/22249)) ([9367e91](https://github.com/angular/angular/commit/9367e91)), closes [#17195](https://github.com/angular/angular/issues/17195)
* **language-service:** do not overwrite native `Reflect` ([#24299](https://github.com/angular/angular/issues/24299)) ([6881404](https://github.com/angular/angular/commit/6881404)), closes [#21420](https://github.com/angular/angular/issues/21420)
* **platform-browser:** add missing deps for HammerGesturesPlugin ([#24682](https://github.com/angular/angular/issues/24682)) ([13d60ea](https://github.com/angular/angular/commit/13d60ea))
* **platform-browser:** mark Meta and Title services as tree shakable providers ([#24815](https://github.com/angular/angular/issues/24815)) ([197387d](https://github.com/angular/angular/commit/197387d))
* **platform-browser:** workaround wrong import path generated by ngc for DOCUMENT ([#24830](https://github.com/angular/angular/issues/24830)) ([7d27ecc](https://github.com/angular/angular/commit/7d27ecc))
* **platform-server:** avoid clash between server and client style encapsulation attributes ([#24158](https://github.com/angular/angular/issues/24158)) ([b96a3c8](https://github.com/angular/angular/commit/b96a3c8))
* **platform-server:** avoid dependency cycle when using http interceptor ([#24229](https://github.com/angular/angular/issues/24229)) ([60aa943](https://github.com/angular/angular/commit/60aa943)), closes [#23023](https://github.com/angular/angular/issues/23023)
* **platform-server:** don't reflect innerHTML property to attribute ([#24213](https://github.com/angular/angular/issues/24213)) ([6a663a4](https://github.com/angular/angular/commit/6a663a4)), closes [#19278](https://github.com/angular/angular/issues/19278)
* **platform-server:** provide Domino DOM types globally ([#24116](https://github.com/angular/angular/issues/24116)) ([c73196e](https://github.com/angular/angular/commit/c73196e)), closes [#23280](https://github.com/angular/angular/issues/23280) [#23133](https://github.com/angular/angular/issues/23133)
* **router:** Fix _lastPathIndex in deeply nested empty paths ([#22394](https://github.com/angular/angular/issues/22394)) ([968f153](https://github.com/angular/angular/commit/968f153))
* **router:** add ability to recover from malformed url ([#23283](https://github.com/angular/angular/issues/23283)) ([86d254d](https://github.com/angular/angular/commit/86d254d)), closes [#21468](https://github.com/angular/angular/issues/21468)
* **router:** fix lazy loading of aux routes ([#23459](https://github.com/angular/angular/issues/23459)) ([5731d07](https://github.com/angular/angular/commit/5731d07)), closes [#10981](https://github.com/angular/angular/issues/10981)
* **router:** avoid freezing queryParams in-place ([#22663](https://github.com/angular/angular/issues/22663)) ([89f64e5](https://github.com/angular/angular/commit/89f64e5)), closes [#22617](https://github.com/angular/angular/issues/22617)
* **router:** cache route handle if found ([#22475](https://github.com/angular/angular/issues/22475)) ([4cfa571](https://github.com/angular/angular/commit/4cfa571)), closes [#22474](https://github.com/angular/angular/issues/22474)
* **router:** correct the segment parsing so it won't break on ampersand ([#23684](https://github.com/angular/angular/issues/23684)) ([553a680](https://github.com/angular/angular/commit/553a680))
* **service-worker:** don't include sourceMappingURL in ngsw-worker ([#24877](https://github.com/angular/angular/issues/24877)) ([8620373](https://github.com/angular/angular/commit/8620373)), closes [#23596](https://github.com/angular/angular/issues/23596)
* **service-worker:** avoid network requests when looking up hashed resources in cache ([#24127](https://github.com/angular/angular/issues/24127)) ([52d43a9](https://github.com/angular/angular/commit/52d43a9))
* **service-worker:** fix `SwPush.unsubscribe()` ([#24162](https://github.com/angular/angular/issues/24162)) ([3ed2d75](https://github.com/angular/angular/commit/3ed2d75)), closes [#24095](https://github.com/angular/angular/issues/24095)
* **service-worker:** add badge to NOTIFICATION_OPTION_NAMES ([#23241](https://github.com/angular/angular/issues/23241)) ([fb59b2d](https://github.com/angular/angular/commit/fb59b2d)), closes [#23196](https://github.com/angular/angular/issues/23196)
* **service-worker:** check platformBrowser before accessing navigator.serviceWorker ([#21231](https://github.com/angular/angular/issues/21231)) ([0bdd30e](https://github.com/angular/angular/commit/0bdd30e))
* **service-worker:** correctly handle requests with empty `clientId` ([#23625](https://github.com/angular/angular/issues/23625)) ([e0ed59e](https://github.com/angular/angular/commit/e0ed59e)), closes [#23526](https://github.com/angular/angular/issues/23526)
* **service-worker:** deprecate `versionedFiles` in asset-group resources ([#23584](https://github.com/angular/angular/issues/23584)) ([1d378e2](https://github.com/angular/angular/commit/1d378e2))
### Features
* **bazel:** Initial commit of protractor_web_test_suite ([#24787](https://github.com/angular/angular/issues/24787)) ([71e0df0](https://github.com/angular/angular/commit/71e0df0))
* **bazel:** protractor_web_test_suite for release ([#24787](https://github.com/angular/angular/issues/24787)) ([161ff5c](https://github.com/angular/angular/commit/161ff5c))
* **common:** introduce KeyValuePipe ([#24319](https://github.com/angular/angular/issues/24319)) ([2b49bf7](https://github.com/angular/angular/commit/2b49bf7))
* **compiler:** support `// ...` and `// TODO` in mock compiler expectations ([#23441](https://github.com/angular/angular/issues/23441)) ([c6b206e](https://github.com/angular/angular/commit/c6b206e))
* **compiler-cli:** update `tsickle` to `0.29.x` ([#24233](https://github.com/angular/angular/issues/24233)) ([f69ac67](https://github.com/angular/angular/commit/f69ac67))
* **core:** export defaultKeyValueDiffers to private api ([#24319](https://github.com/angular/angular/issues/24319)) ([92b278c](https://github.com/angular/angular/commit/92b278c))
* **core:** expose a Compiler API for accessing module ids from NgModule types ([#24258](https://github.com/angular/angular/issues/24258)) ([bd02b27](https://github.com/angular/angular/commit/bd02b27))
* **core:** KeyValueDiffer#diff allows null values ([#24319](https://github.com/angular/angular/issues/24319)) ([52ce9d5](https://github.com/angular/angular/commit/52ce9d5))
* **core:** add support for ShadowDOM v1 ([#24718](https://github.com/angular/angular/issues/24718)) ([3553977](https://github.com/angular/angular/commit/3553977))
(https://github.com/angular/angular/commit/328971f)), closes [#24616](https://github.com/angular/angular/issues/24616)
* **platform-browser:** add HammerJS lazy-loader symbols to public API ([#23943](https://github.com/angular/angular/issues/23943)) ([26fbf1d](https://github.com/angular/angular/commit/26fbf1d))
* **platform-browser:** allow lazy-loading HammerJS ([#23906](https://github.com/angular/angular/issues/23906)) ([313bdce](https://github.com/angular/angular/commit/313bdce))
* **platform-server:** use EventManagerPlugin on the server ([#24132](https://github.com/angular/angular/issues/24132)) ([d6595eb](https://github.com/angular/angular/commit/d6595eb))
* **router:** add urlUpdateStrategy allow updating the browser URL at the beginning of navigation ([#24820](https://github.com/angular/angular/issues/24820)) ([328971f]
* **router:** add navigation execution context info to activation hooks ([#24204](https://github.com/angular/angular/issues/24204)) ([20c463e](https://github.com/angular/angular/commit/20c463e)), closes [#24202](https://github.com/angular/angular/issues/24202)
* **router:** implement scrolling restoration service ([#20030](https://github.com/angular/angular/issues/20030)) ([49c5234](https://github.com/angular/angular/commit/49c5234)), closes [#13636](https://github.com/angular/angular/issues/13636) [#10929](https://github.com/angular/angular/issues/10929) [#7791](https://github.com/angular/angular/issues/7791) [#6595](https://github.com/angular/angular/issues/6595)
* **service-worker:** add support for `?` in SW config globbing ([#24105](https://github.com/angular/angular/issues/24105)) ([250527c](https://github.com/angular/angular/commit/250527c))
* typescript 2.9 support ([#24652](https://github.com/angular/angular/issues/24652)) ([e3064d5](https://github.com/angular/angular/commit/e3064d5))
### build
* **bazel:** turn on preserve-symlinks ([#24881](https://github.com/angular/angular/issues/24881)) ([c438b5e](https://github.com/angular/angular/commit/c438b5e))
### BREAKING CHANGES
* **bazel:** Use of @angular/bazel rules now requires calling ng_setup_workspace() in your WORKSPACE file.
For example:
local_repository(
name = "angular",
path = "node_modules/@angular/bazel",
)
load("@angular//:index.bzl", "ng_setup_workspace")
ng_setup_workspace()
<a name="6.0.9"></a>
## [6.0.9](https://github.com/angular/angular/compare/6.0.8...6.0.9) (2018-07-11)
### Bug Fixes
* **common:** format fractional seconds ([#24844](https://github.com/angular/angular/issues/24844)) ([3c93d07](https://github.com/angular/angular/commit/3c93d07)), closes [#24831](https://github.com/angular/angular/issues/24831)
<a name="6.0.8"></a>
## [6.0.8](https://github.com/angular/angular/compare/6.0.7...6.0.8) (2018-07-11)
### Bug Fixes
* **common:** do not round factional seconds ([#24831](https://github.com/angular/angular/issues/24831)) ([0746485](https://github.com/angular/angular/commit/0746485)), closes [#24384](https://github.com/angular/angular/issues/24384)
* **common:** properly update collection reference in NgForOf ([#24684](https://github.com/angular/angular/issues/24684)) ([9a98de9](https://github.com/angular/angular/commit/9a98de9)), closes [#24155](https://github.com/angular/angular/issues/24155)
* **common:** use correct currency format for locale de-AT ([#24658](https://github.com/angular/angular/issues/24658)) ([a92f111](https://github.com/angular/angular/commit/a92f111)), closes [#24609](https://github.com/angular/angular/issues/24609)
* **compiler-cli:** Use typescript to resolve modules for metadata ([#22856](https://github.com/angular/angular/issues/22856)) ([7717ff1](https://github.com/angular/angular/commit/7717ff1))
* **core:** use addCustomEqualityTester instead of overriding toEqual ([#22983](https://github.com/angular/angular/issues/22983)) ([b8975a9](https://github.com/angular/angular/commit/b8975a9)), closes [#22939](https://github.com/angular/angular/issues/22939)
* **language-service:** do not overwrite native `Reflect` ([#24299](https://github.com/angular/angular/issues/24299)) ([de1c44f](https://github.com/angular/angular/commit/de1c44f)), closes [#21420](https://github.com/angular/angular/issues/21420)
* **router:** add ability to recover from malformed url ([#23283](https://github.com/angular/angular/issues/23283)) ([2d4f4b5](https://github.com/angular/angular/commit/2d4f4b5)), closes [#21468](https://github.com/angular/angular/issues/21468)
* **service-worker:** avoid network requests when looking up hashed resources in cache ([#24127](https://github.com/angular/angular/issues/24127)) ([183b079](https://github.com/angular/angular/commit/183b079))
### Features
* **core:** add support for ShadowDOM v1 ([#24718](https://github.com/angular/angular/issues/24718)) ([6c55a13](https://github.com/angular/angular/commit/6c55a13))
<a name="6.0.7"></a>
## [6.0.7](https://github.com/angular/angular/compare/6.0.6...6.0.7) (2018-06-27)
### Bug Fixes
* **animations:** set animations styles properly on platform-server ([#24624](https://github.com/angular/angular/issues/24624)) ([0b356d4](https://github.com/angular/angular/commit/0b356d4))
* **common:** use correct ICU plural for locale mk ([#24659](https://github.com/angular/angular/issues/24659)) ([64a8584](https://github.com/angular/angular/commit/64a8584))
<a name="6.0.6"></a>
## [6.0.6](https://github.com/angular/angular/compare/6.0.5...6.0.6) (2018-06-20)
### Bug Fixes
* **compiler:** support `.` in import statements. ([#20634](https://github.com/angular/angular/issues/20634)) ([e543c73](https://github.com/angular/angular/commit/e543c73)), closes [#20363](https://github.com/angular/angular/issues/20363)
* **core:** Injector correctly honors the @Self flag ([#24520](https://github.com/angular/angular/issues/24520)) ([f5b3661](https://github.com/angular/angular/commit/f5b3661))
<a name="6.0.5"></a>
## [6.0.5](https://github.com/angular/angular/compare/6.0.4...6.0.5) (2018-06-13)
* **animations:** always render end-state styles for orphaned DOM nodes ([#24236](https://github.com/angular/angular/issues/24236)) ([0139173](https://github.com/angular/angular/commit/0139173))
* **bazel:** Allow ng_module to depend on targets w no deps ([#24446](https://github.com/angular/angular/issues/24446)) ([ea3669e](https://github.com/angular/angular/commit/ea3669e))
* **docs-infra:** use script nomodule to load IE polyfills, skip other polyfills ([#24317](https://github.com/angular/angular/issues/24317)) ([e876535](https://github.com/angular/angular/commit/e876535)), closes [#23647](https://github.com/angular/angular/issues/23647)
* **router:** fix lazy loading of aux routes ([#23459](https://github.com/angular/angular/issues/23459)) ([d20877b](https://github.com/angular/angular/commit/d20877b)), closes [#10981](https://github.com/angular/angular/issues/10981)
* **service-worker:** fix `SwPush.unsubscribe()` ([#24162](https://github.com/angular/angular/issues/24162)) ([ea2987c](https://github.com/angular/angular/commit/ea2987c)), closes [#24095](https://github.com/angular/angular/issues/24095)
<a name="6.0.4"></a>
## [6.0.4](https://github.com/angular/angular/compare/6.0.3...6.0.4) (2018-06-06)
### Bug Fixes
* **animations:** Fix browser detection logic ([#24188](https://github.com/angular/angular/issues/24188)) ([c9eb491](https://github.com/angular/angular/commit/c9eb491))
* **animations:** retain trigger-state for nodes that are moved around ([#24238](https://github.com/angular/angular/issues/24238)) ([19deca1](https://github.com/angular/angular/commit/19deca1))
* **forms:** properly handle special properties in FormGroup.get ([#22249](https://github.com/angular/angular/issues/22249)) ([dc3e8aa](https://github.com/angular/angular/commit/dc3e8aa)), closes [#17195](https://github.com/angular/angular/issues/17195)
* **platform-server:** avoid clash between server and client style encapsulation attributes ([#24158](https://github.com/angular/angular/issues/24158)) ([e9f2203](https://github.com/angular/angular/commit/e9f2203))
* **platform-server:** avoid dependency cycle when using http interceptor ([#24229](https://github.com/angular/angular/issues/24229)) ([2991b1b](https://github.com/angular/angular/commit/2991b1b)), closes [#23023](https://github.com/angular/angular/issues/23023)
* **platform-server:** don't reflect innerHTML property to attibute ([#24213](https://github.com/angular/angular/issues/24213)) ([c17098d](https://github.com/angular/angular/commit/c17098d)), closes [#19278](https://github.com/angular/angular/issues/19278)
* **platform-server:** provide Domino DOM types globally ([#24116](https://github.com/angular/angular/issues/24116)) ([906b3ec](https://github.com/angular/angular/commit/906b3ec)), closes [#23280](https://github.com/angular/angular/issues/23280) [#23133](https://github.com/angular/angular/issues/23133)
<a name="6.0.3"></a>
## [6.0.3](https://github.com/angular/angular/compare/6.0.2...6.0.3) (2018-05-22)
### Bug Fixes
* **service-worker:** check platformBrowser before accessing navigator.serviceWorker ([#21231](https://github.com/angular/angular/issues/21231)) ([0ee5b7e](https://github.com/angular/angular/commit/0ee5b7e))
<a name="6.0.2"></a>
## [6.0.2](https://github.com/angular/angular/compare/6.0.1...6.0.2) (2018-05-15)
### Bug Fixes
* **animations:** do not throw errors when a destroyed component is animated ([#23836](https://github.com/angular/angular/issues/23836)) ([752b83a](https://github.com/angular/angular/commit/752b83a))
* **service-worker:** deprecate `versionedFiles` in asset-group resources ([#23584](https://github.com/angular/angular/issues/23584)) ([c6b618d](https://github.com/angular/angular/commit/c6b618d))
<a name="6.0.1"></a>
# [6.0.1](https://github.com/angular/angular/compare/6.0.0...6.0.1) (2018-05-11)
### Bug Fixes
* **animations:** properly clean up queried element styles in safari/edge ([#23686](https://github.com/angular/angular/issues/23686)) ([3824e3f](https://github.com/angular/angular/commit/3824e3f))
* **animations:** retain state styling for nodes that are moved around ([#23686](https://github.com/angular/angular/issues/23686)) ([05aa5e0](https://github.com/angular/angular/commit/05aa5e0))
* **core:** call ngOnDestroy on all services that have it ([#23755](https://github.com/angular/angular/issues/23755)) ([5581e97](https://github.com/angular/angular/commit/5581e97)), closes [#22466](https://github.com/angular/angular/issues/22466) [#22240](https://github.com/angular/angular/issues/22240) [#14818](https://github.com/angular/angular/issues/14818)
* **elements:** always check to create strategy ([#23825](https://github.com/angular/angular/issues/23825)) ([d280077](https://github.com/angular/angular/commit/d280077))
* **router:** avoid freezing queryParams in-place ([#22663](https://github.com/angular/angular/issues/22663)) ([3d8799b](https://github.com/angular/angular/commit/3d8799b)), closes [#22617](https://github.com/angular/angular/issues/22617)
* **router:** correct the segment parsing so it won't break on ampersand ([#23684](https://github.com/angular/angular/issues/23684)) ([8733843](https://github.com/angular/angular/commit/8733843))
* **service-worker:** correctly handle requests with empty `clientId` ([#23625](https://github.com/angular/angular/issues/23625)) ([2254ac2](https://github.com/angular/angular/commit/2254ac2)), closes [#23526](https://github.com/angular/angular/issues/23526)
<a name="6.0.0"></a>
# [6.0.0](https://github.com/angular/angular/compare/6.0.0-beta.0...6.0.0) (2018-05-03)
### Release Highlights & Update instructions
Angular v6 is the first release of Angular that unifies the Framework, Material and CLI.
To learn about the release highlights and our new CLI-powered update workflow for your projects please check out the [v6 release announcement](https://blog.angular.io/version-6-0-0-of-angular-now-available-cc56b0efa7a4).
# [6.0.0](https://github.com/angular/angular/compare/6.0.0-rc.6...6.0.0) (2018-05-03)
### Dependency updates
@ -283,6 +17,7 @@ To learn about the release highlights and our new CLI-powered update workflow fo
* **animations:** only use the WA-polyfill alongside AnimationBuilder ([#22143](https://github.com/angular/angular/issues/22143)) ([b2f366b](https://github.com/angular/angular/commit/b2f366b)), closes [#17496](https://github.com/angular/angular/issues/17496)
* **animations:** expose `element` and `params` within transition matchers ([#22693](https://github.com/angular/angular/issues/22693)) ([58b94e6](https://github.com/angular/angular/commit/58b94e6))
* **common:** better error message when non-template element used in NgIf ([#22274](https://github.com/angular/angular/issues/22274)) ([67cf11d](https://github.com/angular/angular/commit/67cf11d)), closes [#16410](https://github.com/angular/angular/issues/16410)
* **common:** better error message when non-template element used in NgIf ([#22274](https://github.com/angular/angular/issues/22274)) ([67cf11d](https://github.com/angular/angular/commit/67cf11d)), closes [#16410](https://github.com/angular/angular/issues/16410)
* **common:** export functions to format numbers, percents, currencies & dates ([#22423](https://github.com/angular/angular/issues/22423)) ([4180912](https://github.com/angular/angular/commit/4180912)), closes [#20536](https://github.com/angular/angular/issues/20536)
* **compiler:** lower @NgModule ids if needed ([#23031](https://github.com/angular/angular/issues/23031)) ([bd024c0](https://github.com/angular/angular/commit/bd024c0))
* **compiler:** implement "enableIvy" compiler option ([#21427](https://github.com/angular/angular/issues/21427)) ([64d16de](https://github.com/angular/angular/commit/64d16de))
@ -322,6 +57,7 @@ To learn about the release highlights and our new CLI-powered update workflow fo
* **animations:** report correct totalTime value even during noOp animations ([#22225](https://github.com/angular/angular/issues/22225)) ([e1bf067](https://github.com/angular/angular/commit/e1bf067))
* **animations:** avoid animation insertions during router back/refresh ([#21977](https://github.com/angular/angular/issues/21977)) ([f88fba0](https://github.com/angular/angular/commit/f88fba0)), closes [#19712](https://github.com/angular/angular/issues/19712)
* **animations:** treat numeric state name values as strings ([#22923](https://github.com/angular/angular/issues/22923)) ([e5e1b0d](https://github.com/angular/angular/commit/e5e1b0d))
* **animations:** report correct totalTime value even during noOp animations ([#22225](https://github.com/angular/angular/issues/22225)) ([e1bf067](https://github.com/angular/angular/commit/e1bf067))
* **animations:** fix increment/decrement aliases example ([#18323](https://github.com/angular/angular/issues/18323)) ([d2aa8ac](https://github.com/angular/angular/commit/d2aa8ac))
* **common:** NgClass should properly take className changes into account ([#21937](https://github.com/angular/angular/issues/21937)) ([4a42669](https://github.com/angular/angular/commit/4a42669)), closes [#21932](https://github.com/angular/angular/issues/21932)
* **common:** fix the titlecase pipe ([#22600](https://github.com/angular/angular/issues/22600)) ([7966744](https://github.com/angular/angular/commit/7966744))
@ -401,7 +137,7 @@ To learn about the release highlights and our new CLI-powered update workflow fo
### Possible Breaking Changes
### POSSIBLE BREAKING CHANGES
* **animations:** When animation is triggered within a disabled zone, the associated event (which an instance of AnimationEvent) will no longer report the totalTime as 0 (it will emit the actual time of the animation).

View File

@ -227,15 +227,10 @@ The following is the list of supported scopes:
There are currently a few exceptions to the "use package name" rule:
* **packaging**: used for changes that change the npm package layout in all of our packages, e.g.
public path changes, package.json changes done to all packages, d.ts file/format changes, changes
to bundles, etc.
* **packaging**: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.
* **changelog**: used for updating the release notes in CHANGELOG.md
* **docs-infra**: used for docs-app (angular.io) related changes within the /aio directory of the
repo
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all
packages (e.g. `style: add missing semicolons`) and for docs changes that are not related to a
specific package (e.g. `docs: fix typo in tutorial`).
* **aio**: used for docs-app (angular.io) related changes within the /aio directory of the repo
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`)
### Subject
The subject contains a succinct description of the change:

View File

@ -5,6 +5,10 @@
[![npm version](https://badge.fury.io/js/%40angular%2Fcore.svg)](https://www.npmjs.com/@angular/core)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/angular2-ci.svg)](https://saucelabs.com/u/angular2-ci)
*Safari (7+), iOS (7+) and IE mobile (11) are tested on [BrowserStack][browserstack].*
# Angular
Angular is a development platform for building mobile and desktop web applications using Typescript/JavaScript and other languages.
@ -13,19 +17,12 @@ Angular is a development platform for building mobile and desktop web applicatio
[Get started in 5 minutes][quickstart].
## Changelog
[Learn about the latest improvements][changelog].
## Want to help?
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
guidelines for [contributing][contributing] and then check out one of our issues in the [hotlist: community-help](https://github.com/angular/angular/labels/hotlist%3A%20community-help).
[browserstack]: https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06
[contributing]: https://github.com/angular/angular/blob/master/CONTRIBUTING.md
[quickstart]: https://angular.io/guide/quickstart
[changelog]: https://github.com/angular/angular/blob/master/CHANGELOG.md
[ng]: https://angular.io
[contributing]: http://github.com/angular/angular/blob/master/CONTRIBUTING.md
[quickstart]: https://angular.io/docs/ts/latest/quickstart.html
[ng]: http://angular.io

158
WORKSPACE
View File

@ -1,86 +1,33 @@
workspace(name = "angular")
#
# Download Bazel toolchain dependencies as needed by build actions
#
http_archive(
name = "build_bazel_rules_nodejs",
urls = ["https://github.com/bazelbuild/rules_nodejs/archive/0.11.2.zip"],
strip_prefix = "rules_nodejs-0.11.2",
sha256 = "c00d5381adeefb56e0ef959a7b168cae628535dab933cfad1c2cd1870cd7c9de",
url = "https://github.com/bazelbuild/rules_nodejs/archive/1931156c232a08356dfda02e9c8b0275c2e63c00.zip",
strip_prefix = "rules_nodejs-1931156c232a08356dfda02e9c8b0275c2e63c00",
sha256 = "9cfe33276a6ac0076ee9ee159c4a2576f9851c0f437435b5ac19b2e592493078",
)
http_archive(
name = "bazel_skylib",
urls = ["https://github.com/bazelbuild/bazel-skylib/archive/0.3.1.zip"],
strip_prefix = "bazel-skylib-0.3.1",
sha256 = "95518adafc9a2b656667bbf517a952e54ce7f350779d0dd95133db4eb5c27fb1",
)
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install")
http_archive(
name = "io_bazel_rules_webtesting",
url = "https://github.com/bazelbuild/rules_webtesting/archive/7ffe970bbf380891754487f66c3d680c087d67f2.zip",
strip_prefix = "rules_webtesting-7ffe970bbf380891754487f66c3d680c087d67f2",
sha256 = "4fb0dca8c9a90547891b7ef486592775a523330fc4555c88cd8f09270055c2ce",
check_bazel_version("0.11.1")
node_repositories(package_json = ["//:package.json"])
yarn_install(
name = "ts-api-guardian_runtime_deps",
package_json = "//tools/ts-api-guardian:package.json",
yarn_lock = "//tools/ts-api-guardian:yarn.lock",
)
http_archive(
name = "build_bazel_rules_typescript",
url = "https://github.com/bazelbuild/rules_typescript/archive/1d9a4b0087f307e31af91e2b221a6447288994c6.zip",
strip_prefix = "rules_typescript-1d9a4b0087f307e31af91e2b221a6447288994c6",
sha256 = "e17ac3f33d5d3cd2a0c385c4fd28b814d0ad46c6c67ccaef97160be99d7a24eb",
url = "https://github.com/bazelbuild/rules_typescript/archive/0.12.1.zip",
strip_prefix = "rules_typescript-0.12.1",
sha256 = "24e2c36f60508c6d270ae4265b89b381e3f66d550e70c367ed3755ad8d7ce3b0",
)
http_archive(
name = "io_bazel_rules_go",
url = "https://github.com/bazelbuild/rules_go/releases/download/0.10.3/rules_go-0.10.3.tar.gz",
sha256 = "feba3278c13cde8d67e341a837f69a029f698d7a27ddbb2a202be7a10b22142a",
)
load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace")
# This commit matches the version of buildifier in angular/ngcontainer
# If you change this, also check if it matches the version in the angular/ngcontainer
# version in /.circleci/config.yml
BAZEL_BUILDTOOLS_VERSION = "82b21607e00913b16fe1c51bec80232d9d6de31c"
http_archive(
name = "com_github_bazelbuild_buildtools",
url = "https://github.com/bazelbuild/buildtools/archive/%s.zip" % BAZEL_BUILDTOOLS_VERSION,
strip_prefix = "buildtools-%s" % BAZEL_BUILDTOOLS_VERSION,
sha256 = "edb24c2f9c55b10a820ec74db0564415c0cf553fa55e9fc709a6332fb6685eff",
)
# Fetching the Bazel source code allows us to compile the Skylark linter
http_archive(
name = "io_bazel",
url = "https://github.com/bazelbuild/bazel/archive/968f87900dce45a7af749a965b72dbac51b176b3.zip",
strip_prefix = "bazel-968f87900dce45a7af749a965b72dbac51b176b3",
sha256 = "e373d2ae24955c1254c495c9c421c009d88966565c35e4e8444c082cb1f0f48f",
)
# We have a source dependency on the Devkit repository, because it's built with
# Bazel.
# This allows us to edit sources and have the effect appear immediately without
# re-packaging or "npm link"ing.
# Even better, things like aspects will visit the entire graph including
# ts_library rules in the devkit repository.
http_archive(
name = "angular_cli",
url = "https://github.com/angular/angular-cli/archive/v6.1.0-rc.0.zip",
strip_prefix = "angular-cli-6.1.0-rc.0",
sha256 = "8cf320ea58c321e103f39087376feea502f20eaf79c61a4fdb05c7286c8684fd",
)
http_archive(
name = "org_brotli",
url = "https://github.com/google/brotli/archive/f9b8c02673c576a3e807edbf3a9328e9e7af6d7c.zip",
strip_prefix = "brotli-f9b8c02673c576a3e807edbf3a9328e9e7af6d7c",
sha256 = "8a517806d2b7c8505ba5c53934e7d7c70d341b68ffd268e9044d35b564a48828",
)
#
# Point Bazel to WORKSPACEs that live in subdirectories
#
ts_setup_workspace()
local_repository(
name = "rxjs",
@ -94,53 +41,54 @@ local_repository(
path = "integration/bazel",
)
#
# Load and install our dependencies downloaded above.
#
# This commit matches the version of buildifier in angular/ngcontainer
# If you change this, also check if it matches the version in the angular/ngcontainer
# version in /.circleci/config.yml
BAZEL_BUILDTOOLS_VERSION = "70bc7843bb9950fece2bc014ed16de03419e36e2"
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install")
http_archive(
name = "com_github_bazelbuild_buildtools",
url = "https://github.com/bazelbuild/buildtools/archive/%s.zip" % BAZEL_BUILDTOOLS_VERSION,
strip_prefix = "buildtools-%s" % BAZEL_BUILDTOOLS_VERSION,
sha256 = "367c23a5fe7fc2a7cb57863d3718b4149f0e57426c48c8ad54c45348a0b53cc1",
)
check_bazel_version("0.15.0")
node_repositories(
package_json = ["//:package.json"],
preserve_symlinks = True,
http_archive(
name = "io_bazel_rules_go",
url = "https://github.com/bazelbuild/rules_go/releases/download/0.10.3/rules_go-0.10.3.tar.gz",
sha256 = "feba3278c13cde8d67e341a837f69a029f698d7a27ddbb2a202be7a10b22142a",
)
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
go_rules_dependencies()
go_register_toolchains()
load("@io_bazel_rules_webtesting//web:repositories.bzl", "browser_repositories", "web_test_repositories")
web_test_repositories()
browser_repositories(
chromium = True,
firefox = True,
# Fetching the Bazel source code allows us to compile the Skylark linter
http_archive(
name = "io_bazel",
url = "https://github.com/bazelbuild/bazel/archive/5a35e72f9e97c06540c479f8c31512fb4656202f.zip",
strip_prefix = "bazel-5a35e72f9e97c06540c479f8c31512fb4656202f",
sha256 = "ed33a52874c14e3b487fb50f390c541fab9c81a33d986d38fb01766a66dbcd21",
)
load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace")
ts_setup_workspace()
load("@angular//:index.bzl", "ng_setup_workspace")
ng_setup_workspace()
#
# Ask Bazel to manage these toolchain dependencies for us.
# Bazel will run `yarn install` when one of these toolchains is requested during
# a build.
#
yarn_install(
name = "ts-api-guardian_runtime_deps",
package_json = "//tools/ts-api-guardian:package.json",
yarn_lock = "//tools/ts-api-guardian:yarn.lock",
# We have a source dependency on the Devkit repository, because it's built with
# Bazel.
# This allows us to edit sources and have the effect appear immediately without
# re-packaging or "npm link"ing.
# Even better, things like aspects will visit the entire graph including
# ts_library rules in the devkit repository.
http_archive(
name = "angular_devkit",
url = "https://github.com/angular/devkit/archive/v0.3.1.zip",
strip_prefix = "devkit-0.3.1",
sha256 = "31d4b597fe9336650acf13df053c1c84dcbe9c29c6a833bcac3819cd3fd8cad3",
)
yarn_install(
name = "http-server_runtime_deps",
package_json = "//tools/http-server:package.json",
yarn_lock = "//tools/http-server:yarn.lock",
http_archive(
name = "org_brotli",
url = "https://github.com/google/brotli/archive/c6333e1e79fb62ea088443f192293f964409b04e.zip",
strip_prefix = "brotli-c6333e1e79fb62ea088443f192293f964409b04e",
sha256 = "3f781988dee7dd3bcce2bf238294663cfaaf3b6433505bdb762e24d0a284d1dc",
)

View File

@ -43,17 +43,6 @@ Here are the most important tasks you might need to use:
* `yarn build-ie-polyfills` - generates a js file of polyfills that can be loaded in Internet Explorer.
## Developing on Windows
The `packages/` directory may contain Linux-specific symlinks, which are not recognized by Windows.
These unresolved links cause the docs generation process to fail because it cannot locate certain files.
> Hint: The following steps require administration rights or [Windows Developer Mode](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development) enabled!
To fix this problem, run `scripts/windows/create-symlinks.sh`. This command creates temporary files where the symlinks used to be. Make sure not to commit those files with your documentation changes.
When you are done making and testing your documentation changes, you can restore the original symlinks and delete the temporary files by running `scripts/windows/remove-symlinks.sh`.
It's necessary to remove the temporary files, because otherwise they're displayed as local changes in your git working copy and certain operations are blocked.
## Using ServiceWorker locally
Since abb36e3cb, running `yarn start --prod` will no longer set up the ServiceWorker, which

View File

@ -52,7 +52,8 @@ export class BuildCleaner {
protected removeDir(dir: string) {
try {
if (shell.test('-d', dir)) {
shell.chmod('-R', 'a+w', dir);
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
(shell as any).chmod('-R', 'a+w', dir);
shell.rm('-rf', dir);
}
} catch (err) {

View File

@ -106,7 +106,8 @@ export class BuildCreator extends EventEmitter {
}
try {
shell.chmod('-R', 'a-w', outputDir);
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
(shell as any).chmod('-R', 'a-w', outputDir);
shell.rm('-f', inputFile);
resolve();
} catch (err) {

View File

@ -98,7 +98,8 @@ class Helper {
const prDir = this.getPrDir(pr, isPublic);
if (fs.existsSync(prDir)) {
shell.chmod('-R', 'a+w', prDir);
// Undocumented signature (see https://github.com/shelljs/shelljs/pull/663).
(shell as any).chmod('-R', 'a+w', prDir);
shell.rm('-rf', prDir);
}
}

View File

@ -8,7 +8,7 @@
"scripts": {
"prebuild": "yarn clean-dist",
"build": "tsc",
"build-watch": "yarn build --watch",
"build-watch": "yarn tsc --watch",
"clean-dist": "node --eval \"require('shelljs').rm('-rf', 'dist')\"",
"dev": "concurrently --kill-others --raw --success first \"yarn build-watch\" \"yarn test-watch\"",
"lint": "tslint --project tsconfig.json",
@ -33,7 +33,7 @@
"@types/jasmine": "^2.6.0",
"@types/jsonwebtoken": "^7.2.3",
"@types/node": "^8.0.30",
"@types/shelljs": "^0.8.0",
"@types/shelljs": "^0.7.4",
"@types/supertest": "^2.0.3",
"concurrently": "^3.5.0",
"nodemon": "^1.12.1",

View File

@ -69,9 +69,9 @@
"@types/express-serve-static-core" "*"
"@types/mime" "*"
"@types/shelljs@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.0.tgz#0caa56b68baae4f68f44e0dd666ab30b098e3632"
"@types/shelljs@^0.7.4":
version "0.7.4"
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.7.4.tgz#137b5f31306eaff4de120ffe5b9d74b297809cfc"
dependencies:
"@types/glob" "*"
"@types/node" "*"

View File

@ -3,7 +3,7 @@
set -eux -o pipefail
exec 3>&1
echo -e "\n\n[`date`] - Updating the preview server..."
echo "\n\n[`date`] - Updating the preview server..."
# Input
readonly HOST_REPO_DIR=$1

View File

@ -8,7 +8,6 @@
"projects": {
"site": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"architect": {
"build": {
@ -30,12 +29,36 @@
"vendorChunk": false,
"polyfills": "src/polyfills.ts",
"assets": [
"src/assets",
"src/generated",
"src/app/search/search-worker.js",
"src/favicon.ico",
"src/pwa-manifest.json",
"src/google385281288605d160.html",
{
"glob": "**/*",
"input": "src/assets",
"output": "/assets"
},
{
"glob": "**/*",
"input": "src/generated",
"output": "/generated"
},
{
"glob": "app/search/search-worker.js",
"input": "src",
"output": "/"
},
{
"glob": "favicon.ico",
"input": "src",
"output": "/"
},
{
"glob": "pwa-manifest.json",
"input": "src",
"output": "/"
},
{
"glob": "google385281288605d160.html",
"input": "src",
"output": "/"
},
{
"glob": "custom-elements.min.js",
"input": "node_modules/@webcomponents/custom-elements",
@ -48,7 +71,9 @@
}
],
"styles": [
"src/styles.scss"
{
"input": "src/styles.scss"
}
],
"scripts": []
},
@ -117,15 +142,41 @@
"tsConfig": "src/tsconfig.spec.json",
"scripts": [],
"styles": [
"src/styles.scss"
{
"input": "src/styles.scss"
}
],
"assets": [
"src/assets",
"src/generated",
"src/app/search/search-worker.js",
"src/favicon.ico",
"src/pwa-manifest.json",
"src/google385281288605d160.html",
{
"glob": "**/*",
"input": "src/assets",
"output": "/assets"
},
{
"glob": "**/*",
"input": "src/generated",
"output": "/generated"
},
{
"glob": "app/search/search-worker.js",
"input": "src",
"output": "/"
},
{
"glob": "favicon.ico",
"input": "src",
"output": "/"
},
{
"glob": "pwa-manifest.json",
"input": "src",
"output": "/"
},
{
"glob": "google385281288605d160.html",
"input": "src",
"output": "/"
},
{
"glob": "custom-elements.min.js",
"input": "node_modules/@webcomponents/custom-elements",

BIN
aio/content/examples/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -60,8 +60,6 @@ dist/
!rollup-config.js
aot-compiler/**/*.d.ts
aot-compiler/**/*.factory.d.ts
upgrade-phonecat-2-hybrid/aot/**/*
!upgrade-phonecat-2-hybrid/aot/index.html
# i18n
!i18n/src/systemjs-text-plugin.js

View File

@ -40,7 +40,5 @@ export class HighlightDirective {
// #docregion color-2
@Input() appHighlight: string;
// #enddocregion color-2
// #docregion
}
// #enddocregion

View File

@ -5,7 +5,7 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
// #docregion directive-import
@ -24,7 +24,7 @@ import { ItemDirective } from './item.directive';
imports: [
BrowserModule,
FormsModule,
HttpClientModule
HttpModule
],
providers: [],
bootstrap: [AppComponent]

View File

@ -0,0 +1,27 @@
# MasterProject
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.0.0-rc.0.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
Before running the tests make sure you are serving the app via `ng serve`.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

View File

@ -5,18 +5,18 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
selector: 'app-voter',
template: `
<h4>{{name}}</h4>
<button (click)="vote(true)" [disabled]="didVote">Agree</button>
<button (click)="vote(false)" [disabled]="didVote">Disagree</button>
<button (click)="vote(true)" [disabled]="voted">Agree</button>
<button (click)="vote(false)" [disabled]="voted">Disagree</button>
`
})
export class VoterComponent {
@Input() name: string;
@Output() voted = new EventEmitter<boolean>();
didVote = false;
@Output() onVoted = new EventEmitter<boolean>();
voted = false;
vote(agreed: boolean) {
this.voted.emit(agreed);
this.didVote = true;
this.onVoted.emit(agreed);
this.voted = true;
}
}
// #enddocregion

View File

@ -8,7 +8,7 @@ import { Component } from '@angular/core';
<h3>Agree: {{agreed}}, Disagree: {{disagreed}}</h3>
<app-voter *ngFor="let voter of voters"
[name]="voter"
(voted)="onVoted($event)">
(onVoted)="onVoted($event)">
</app-voter>
`
})

View File

@ -1,7 +1,7 @@
// #docregion
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { HttpModule } from '@angular/http';
// import { AppRoutingModule } from './app-routing.module';
import { LocationStrategy,
@ -54,7 +54,7 @@ const c_components = [
imports: [
BrowserModule,
FormsModule,
HttpClientModule,
HttpModule,
InMemoryWebApiModule.forRoot(HeroData)
// AppRoutingModule TODO: add routes
],

View File

@ -1,38 +1,26 @@
import { Injector } from '@angular/core';
import { ReflectiveInjector } from '@angular/core';
import { Car, Engine, Tires } from './car';
import { Logger } from '../logger.service';
// #docregion injector
export function useInjector() {
let injector: Injector;
let injector: ReflectiveInjector;
// #enddocregion injector
/*
// #docregion injector-no-new
// Cannot instantiate an Injector like this!
let injector = new Injector([
{ provide: Car, deps: [Engine, Tires] },
{ provide: Engine, deps: [] },
{ provide: Tires, deps: [] }
]);
// Cannot instantiate an ReflectiveInjector like this!
let injector = new ReflectiveInjector([Car, Engine, Tires]);
// #enddocregion injector-no-new
*/
// #docregion injector, injector-create-and-call
injector = Injector.create({
providers: [
{ provide: Car, deps: [Engine, Tires] },
{ provide: Engine, deps: [] },
{ provide: Tires, deps: [] }
]
});
injector = ReflectiveInjector.resolveAndCreate([Car, Engine, Tires]);
// #docregion injector-call
let car = injector.get(Car);
// #enddocregion injector-call, injector-create-and-call
car.description = 'Injector';
injector = Injector.create({
providers: [{ provide: Logger, deps: [] }]
});
injector = ReflectiveInjector.resolveAndCreate([Logger]);
let logger = injector.get(Logger);
logger.log('Injector car.drive() said: ' + car.drive());
return car;

View File

@ -1,69 +0,0 @@
'use strict'; // necessary for es6 output in node
import { browser, by, element } from 'protractor';
/* tslint:disable:quotemark */
describe('Elements', () => {
const messageInput = element(by.css('input'));
const popupButtons = element.all(by.css('button'));
beforeEach(() => browser.get(''));
describe('popup component', () => {
const popupComponentButton = popupButtons.get(0);
const popupComponent = element(by.css('popup-component'));
const closeButton = popupComponent.element(by.css('button'));
it('should be displayed on button click', () => {
expect(popupComponent.isPresent()).toBe(false);
popupComponentButton.click();
expect(popupComponent.isPresent()).toBe(true);
});
it('should display the specified message', () => {
messageInput.clear();
messageInput.sendKeys('Angular rocks!');
popupComponentButton.click();
expect(popupComponent.getText()).toContain('Popup: Angular rocks!');
});
it('should be closed on "close" button click', () => {
popupComponentButton.click();
expect(popupComponent.isPresent()).toBe(true);
closeButton.click();
expect(popupComponent.isPresent()).toBe(false);
});
});
describe('popup element', () => {
const popupElementButton = popupButtons.get(1);
const popupElement = element(by.css('popup-element'));
const closeButton = popupElement.element(by.css('button'));
it('should be displayed on button click', () => {
expect(popupElement.isPresent()).toBe(false);
popupElementButton.click();
expect(popupElement.isPresent()).toBe(true);
});
it('should display the specified message', () => {
messageInput.clear();
messageInput.sendKeys('Angular rocks!');
popupElementButton.click();
expect(popupElement.getText()).toContain('Popup: Angular rocks!');
});
it('should be closed on "close" button click', () => {
popupElementButton.click();
expect(popupElement.isPresent()).toBe(true);
closeButton.click();
expect(popupElement.isPresent()).toBe(false);
});
});
});

View File

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

View File

@ -1,5 +1,6 @@
// #docregion
import { Component, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { createNgElementConstructor } from '../elements-dist';
import { PopupService } from './popup.service';
import { PopupComponent } from './popup.component';
@ -7,15 +8,19 @@ import { PopupComponent } from './popup.component';
selector: 'app-root',
template: `
<input #input value="Message">
<button (click)="popup.showAsComponent(input.value)">Show as component</button>
<button (click)="popup.showAsElement(input.value)">Show as element</button>
`,
<button (click)="popup.showAsComponent(input.value)">
Show as component </button>
<button (click)="popup.showAsElement(input.value)">
Show as element </button>
`
})
export class AppComponent {
constructor(injector: Injector, public popup: PopupService) {
// Convert `PopupComponent` to a custom element.
const PopupElement = createCustomElement(PopupComponent, {injector});
// Register the custom element with the browser.
customElements.define('popup-element', PopupElement);
constructor(private injector: Injector, public popup: PopupService) {
// on init, convert PopupComponent to a custom element
const PopupElement =
createNgElementConstructor(PopupComponent, {injector: this.injector});
// register the custom element with the browser.
customElements.define('popup-element', PopupElement);
}
}

View File

@ -1,21 +1,22 @@
import { NgModule } from '@angular/core';
// #docregion
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { PopupComponent } from './popup.component';
import { PopupService } from './popup.service';
import { PopupComponent } from './popup.component';
// Include the `PopupService` provider,
// but exclude `PopupComponent` from compilation,
// because it will be added dynamically.
// include the PopupService provider,
// but exclude PopupComponent from compilation,
// because it will be added dynamically
@NgModule({
declarations: [AppComponent, PopupComponent],
imports: [BrowserModule, BrowserAnimationsModule],
providers: [PopupService],
declarations: [AppComponent, PopupComponent],
bootstrap: [AppComponent],
entryComponents: [PopupComponent],
})
export class AppModule {
}
export class AppModule {}

View File

@ -1,14 +1,14 @@
// #docregion
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { AnimationEvent } from '@angular/animations';
import { animate, state, style, transition, trigger } from '@angular/animations';
@Component({
selector: 'my-popup',
template: `
<span>Popup: {{message}}</span>
<button (click)="closed.next()">&#x2716;</button>
`,
template: 'Popup: {{message}}',
host: {
'[@state]': 'state',
'(@state.done)': 'onAnimationDone($event)',
},
animations: [
trigger('state', [
@ -27,17 +27,13 @@ import { animate, state, style, transition, trigger } from '@angular/animations'
height: 48px;
padding: 16px;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid black;
font-size: 24px;
}
button {
border-radius: 50%;
}
`]
})
export class PopupComponent {
private state: 'opened' | 'closed' = 'closed';
@ -45,10 +41,18 @@ export class PopupComponent {
set message(message: string) {
this._message = message;
this.state = 'opened';
setTimeout(() => this.state = 'closed', 2000);
}
get message(): string { return this._message; }
_message: string;
@Output()
closed = new EventEmitter();
onAnimationDone(e: AnimationEvent) {
if (e.toState === 'closed') {
this.closed.next();
}
}
}

View File

@ -1,8 +1,9 @@
// #docregion
import { ApplicationRef, ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
import { NgElement, WithProperties } from '@angular/elements';
import { PopupComponent } from './popup.component';
import { PopupComponent } from './popup.component';
import { NgElementConstructor } from '../elements-dist';
@Injectable()
export class PopupService {
@ -39,7 +40,7 @@ export class PopupService {
// This uses the new custom-element method to add the popup to the DOM.
showAsElement(message: string) {
// Create element
const popupEl: NgElement & WithProperties<PopupComponent> = document.createElement('popup-element') as any;
const popupEl = document.createElement('popup-element');
// Listen to the close event
popupEl.addEventListener('closed', () => document.body.removeChild(popupEl));

View File

@ -1,9 +0,0 @@
{
"description": "Angular Elements",
"files":[
"!**/*.d.ts",
"!**/*.js",
"!**/*.[1].*"
],
"tags":["cookbook"]
}

View File

@ -1,14 +1,15 @@
// #docplaster
// #docregion app-module
import { HttpClientModule } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
// import the feature module here so you can add it to the imports array below
import { CustomerDashboardModule } from './customer-dashboard/customer-dashboard.module';
@NgModule({
declarations: [
AppComponent
@ -16,7 +17,7 @@ import { CustomerDashboardModule } from './customer-dashboard/customer-dashboard
imports: [
BrowserModule,
FormsModule,
HttpClientModule,
HttpModule,
CustomerDashboardModule // add the feature module here
],
providers: [],

View File

@ -16,7 +16,6 @@ describe('Form Validation Tests', function () {
tests('Template-Driven Form');
bobTests();
crossValidationTests();
});
describe('Reactive form', () => {
@ -26,7 +25,6 @@ describe('Form Validation Tests', function () {
tests('Reactive Form');
bobTests();
crossValidationTests();
});
});
@ -44,8 +42,7 @@ let page: {
powerOption: ElementFinder,
errorMessages: ElementArrayFinder,
heroFormButtons: ElementArrayFinder,
heroSubmitted: ElementFinder,
crossValidationErrorMessage: ElementFinder,
heroSubmitted: ElementFinder
};
function getPage(sectionTag: string) {
@ -62,8 +59,7 @@ function getPage(sectionTag: string) {
powerOption: section.element(by.css('#power option')),
errorMessages: section.all(by.css('div.alert')),
heroFormButtons: buttons,
heroSubmitted: section.element(by.css('.submitted-message')),
crossValidationErrorMessage: section.element(by.css('.cross-validation-error-message')),
heroSubmitted: section.element(by.css('.submitted-message'))
};
}
@ -176,29 +172,3 @@ function bobTests() {
expectFormIsValid();
});
}
function crossValidationTests() {
const emsg = 'Name cannot match alter ego.';
it(`should produce "${emsg}" error after setting name and alter ego to the same value`, function () {
page.nameInput.clear();
page.nameInput.sendKeys('Batman');
page.alterEgoInput.clear();
page.alterEgoInput.sendKeys('Batman');
expectFormIsInvalid();
expect(page.crossValidationErrorMessage.getText()).toBe(emsg);
});
it('should be ok again with different values', function () {
page.nameInput.clear();
page.nameInput.sendKeys('Batman');
page.alterEgoInput.clear();
page.alterEgoInput.sendKeys('Superman');
expectFormIsValid();
expect(page.crossValidationErrorMessage.isPresent()).toBe(false);
});
}

View File

@ -7,7 +7,7 @@ import { AppComponent } from './app.component';
import { HeroFormTemplateComponent } from './template/hero-form-template.component';
import { HeroFormReactiveComponent } from './reactive/hero-form-reactive.component';
import { ForbiddenValidatorDirective } from './shared/forbidden-name.directive';
import { IdentityRevealedValidatorDirective } from './shared/identity-revealed.directive';
@NgModule({
imports: [
@ -19,8 +19,7 @@ import { IdentityRevealedValidatorDirective } from './shared/identity-revealed.d
AppComponent,
HeroFormTemplateComponent,
HeroFormReactiveComponent,
ForbiddenValidatorDirective,
IdentityRevealedValidatorDirective
ForbiddenValidatorDirective
],
bootstrap: [ AppComponent ]
})

View File

@ -1,42 +0,0 @@
/* tslint:disable: member-ordering forin */
// #docplaster
// #docregion
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { forbiddenNameValidator } from '../shared/forbidden-name.directive';
@Component({
selector: 'app-hero-form-reactive',
templateUrl: './hero-form-reactive.component.html',
styleUrls: ['./hero-form-reactive.component.css'],
})
export class HeroFormReactiveComponent implements OnInit {
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
heroForm: FormGroup;
// #docregion form-group
ngOnInit(): void {
// #docregion custom-validator
this.heroForm = new FormGroup({
'name': new FormControl(this.hero.name, [
Validators.required,
Validators.minLength(4),
forbiddenNameValidator(/bob/i) // <-- Here's how you pass in the custom validator.
]),
'alterEgo': new FormControl(this.hero.alterEgo),
'power': new FormControl(this.hero.power, Validators.required)
});
// #enddocregion custom-validator
}
get name() { return this.heroForm.get('name'); }
get power() { return this.heroForm.get('power'); }
// #enddocregion form-group
}
// #enddocregion

View File

@ -1,5 +0,0 @@
/* #docregion cross-validation-error-css */
.cross-validation-error input {
border-left: 5px solid red;
}
/* #enddocregion cross-validation-error-css */

View File

@ -7,41 +7,33 @@
<div [hidden]="formDir.submitted">
<div class="cross-validation" [class.cross-validation-error]="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)">
<div class="form-group">
<div class="form-group">
<label for="name">Name</label>
<!-- #docregion name-with-error-msg -->
<input id="name" class="form-control"
formControlName="name" required >
<label for="name">Name</label>
<!-- #docregion name-with-error-msg -->
<input id="name" class="form-control"
formControlName="name" required >
<div *ngIf="name.invalid && (name.dirty || name.touched)"
class="alert alert-danger">
<div *ngIf="name.invalid && (name.dirty || name.touched)"
class="alert alert-danger">
<div *ngIf="name.errors.required">
Name is required.
</div>
<div *ngIf="name.errors.minlength">
Name must be at least 4 characters long.
</div>
<div *ngIf="name.errors.forbiddenName">
Name cannot be Bob.
</div>
<div *ngIf="name.errors.required">
Name is required.
</div>
<div *ngIf="name.errors.minlength">
Name must be at least 4 characters long.
</div>
<div *ngIf="name.errors.forbiddenName">
Name cannot be Bob.
</div>
<!-- #enddocregion name-with-error-msg -->
</div>
<!-- #enddocregion name-with-error-msg -->
</div>
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input id="alterEgo" class="form-control"
formControlName="alterEgo" >
</div>
<!-- #docregion cross-validation-error-message -->
<div *ngIf="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)" class="cross-validation-error-message alert alert-danger">
Name cannot match alter ego.
</div>
<!-- #enddocregion cross-validation-error-message -->
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input id="alterEgo" class="form-control"
formControlName="alterEgo" >
</div>
<div class="form-group">

View File

@ -1,36 +1,40 @@
/* tslint:disable: member-ordering forin */
// #docplaster
// #docregion
import { Component, OnInit } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { forbiddenNameValidator } from '../shared/forbidden-name.directive';
import { identityRevealedValidator } from '../shared/identity-revealed.directive';
@Component({
selector: 'app-hero-form-reactive',
templateUrl: './hero-form-reactive.component.html',
styleUrls: ['./hero-form-reactive.component.css'],
templateUrl: './hero-form-reactive.component.html'
})
export class HeroFormReactiveComponent implements OnInit {
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
hero = { name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0] };
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
heroForm: FormGroup;
// #docregion form-group
ngOnInit(): void {
// #docregion custom-validator
this.heroForm = new FormGroup({
'name': new FormControl(this.hero.name, [
Validators.required,
Validators.minLength(4),
forbiddenNameValidator(/bob/i)
forbiddenNameValidator(/bob/i) // <-- Here's how you pass in the custom validator.
]),
'alterEgo': new FormControl(this.hero.alterEgo),
'power': new FormControl(this.hero.power, Validators.required)
}, { validators: identityRevealedValidator }); // <-- add custom validator at the FormGroup level
});
// #enddocregion custom-validator
}
get name() { return this.heroForm.get('name'); }
get power() { return this.heroForm.get('power'); }
// #enddocregion form-group
}
// #enddocregion

View File

@ -5,7 +5,7 @@ import { AbstractControl, NG_VALIDATORS, Validator, ValidatorFn, Validators } fr
// #docregion custom-validator
/** A hero's name can't match the given regular expression */
export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} | null => {
return (control: AbstractControl): {[key: string]: any} => {
const forbidden = nameRe.test(control.value);
return forbidden ? {'forbiddenName': {value: control.value}} : null;
};
@ -22,7 +22,7 @@ export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
export class ForbiddenValidatorDirective implements Validator {
@Input('appForbiddenName') forbiddenName: string;
validate(control: AbstractControl): {[key: string]: any} | null {
validate(control: AbstractControl): {[key: string]: any} {
return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control)
: null;
}

View File

@ -1,25 +0,0 @@
// #docregion
import { Directive } from '@angular/core';
import { AbstractControl, FormGroup, NG_VALIDATORS, ValidationErrors, Validator, ValidatorFn } from '@angular/forms';
// #docregion cross-validation-validator
/** A hero's name can't match the hero's alter ego */
export const identityRevealedValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
const name = control.get('name');
const alterEgo = control.get('alterEgo');
return name && alterEgo && name.value === alterEgo.value ? { 'identityRevealed': true } : null;
};
// #enddocregion cross-validation-validator
// #docregion cross-validation-directive
@Directive({
selector: '[appIdentityRevealed]',
providers: [{ provide: NG_VALIDATORS, useExisting: IdentityRevealedValidatorDirective, multi: true }]
})
export class IdentityRevealedValidatorDirective implements Validator {
validate(control: AbstractControl): ValidationErrors {
return identityRevealedValidator(control)
}
}
// #enddocregion cross-validation-directive

View File

@ -1,4 +0,0 @@
/* #docregion */
.cross-validation-error input {
border-left: 5px solid red;
}

View File

@ -2,48 +2,41 @@
<div class="container">
<h1>Template-Driven Form</h1>
<!-- #docregion cross-validation-register-validator -->
<form #heroForm="ngForm" appIdentityRevealed>
<!-- #enddocregion cross-validation-register-validator -->
<!-- #docregion form-tag-->
<form #heroForm="ngForm">
<!-- #enddocregion form-tag-->
<div [hidden]="heroForm.submitted">
<div class="cross-validation" [class.cross-validation-error]="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)">
<div class="form-group">
<label for="name">Name</label>
<!-- #docregion name-with-error-msg -->
<!-- #docregion name-input -->
<input id="name" name="name" class="form-control"
required minlength="4" appForbiddenName="bob"
[(ngModel)]="hero.name" #name="ngModel" >
<!-- #enddocregion name-input -->
<div *ngIf="name.invalid && (name.dirty || name.touched)"
class="alert alert-danger">
<div class="form-group">
<label for="name">Name</label>
<!-- #docregion name-with-error-msg -->
<!-- #docregion name-input -->
<input id="name" name="name" class="form-control"
required minlength="4" appForbiddenName="bob"
[(ngModel)]="hero.name" #name="ngModel" >
<!-- #enddocregion name-input -->
<div *ngIf="name.errors.required">
Name is required.
</div>
<div *ngIf="name.errors.minlength">
Name must be at least 4 characters long.
</div>
<div *ngIf="name.errors.forbiddenName">
Name cannot be Bob.
</div>
<div *ngIf="name.invalid && (name.dirty || name.touched)"
class="alert alert-danger">
<div *ngIf="name.errors.required">
Name is required.
</div>
<div *ngIf="name.errors.minlength">
Name must be at least 4 characters long.
</div>
<div *ngIf="name.errors.forbiddenName">
Name cannot be Bob.
</div>
<!-- #enddocregion name-with-error-msg -->
</div>
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input id="alterEgo" class="form-control"
name="alterEgo" [(ngModel)]="hero.alterEgo" >
</div>
<!-- #enddocregion name-with-error-msg -->
</div>
<!-- #docregion cross-validation-error-message -->
<div *ngIf="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)" class="cross-validation-error-message alert alert-danger">
Name cannot match alter ego.
</div>
<!-- #enddocregion cross-validation-error-message -->
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input id="alterEgo" class="form-control"
name="alterEgo" [(ngModel)]="hero.alterEgo" >
</div>
<div class="form-group">
@ -69,4 +62,5 @@
<button (click)="heroForm.resetForm({})">Add new hero</button>
</div>
</form>
</div>

View File

@ -3,11 +3,9 @@
// #docregion
import { Component } from '@angular/core';
// #docregion component
@Component({
selector: 'app-hero-form-template',
templateUrl: './hero-form-template.component.html',
styleUrls: ['./hero-form-template.component.css'],
templateUrl: './hero-form-template.component.html'
})
export class HeroFormTemplateComponent {
@ -16,4 +14,3 @@ export class HeroFormTemplateComponent {
hero = {name: 'Dr.', alterEgo: 'Dr. What', power: this.powers[0]};
}
// #enddocregion

View File

@ -2,7 +2,6 @@
"description": "Validation",
"files":[
"!**/*.d.ts",
"!**/*.js",
"!**/*.[1].*"
"!**/*.js"
]
}

View File

@ -1,9 +1,9 @@
import { HttpClientModule } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
@ -13,7 +13,7 @@ import { AppComponent } from './app.component';
imports: [
BrowserModule,
FormsModule,
HttpClientModule,
HttpModule,
AppRoutingModule
],
providers: [],

View File

@ -38,6 +38,8 @@ export class MyCounterComponent implements OnChanges {
}
}
/***************************************/
@Component({
selector: 'counter-parent',
template: `

View File

@ -72,6 +72,8 @@ export class DoCheckComponent implements DoCheck {
}
}
/***************************************/
@Component({
selector: 'do-check-parent',
templateUrl: './do-check-parent.component.html',

View File

@ -46,6 +46,8 @@ export class OnChangesComponent implements OnChanges {
reset() { this.changeLog = []; }
}
/***************************************/
@Component({
selector: 'on-changes-parent',
templateUrl: './on-changes-parent.component.html',

View File

@ -4,8 +4,7 @@ button {
font-size: 100%;
}
code,
.code {
code, .code {
background-color: #eee;
color: black;
font-family: Courier, sans-serif;
@ -22,18 +21,14 @@ div.code {
}
hr {
margin: 40px 0;
margin: 40px 0
}
td,
th {
td, th {
text-align: left;
vertical-align: top;
}
/* #docregion p-span */
p span {
color: red;
font-size: 70%;
}
p span { color: red; font-size: 70%; }
/* #enddocregion p-span */

View File

@ -132,7 +132,7 @@
<!-- #docregion select-span -->
<select [(ngModel)]="hero">
<span *ngFor="let h of heroes">
<span *ngIf="showSad || h?.emotion !== 'sad'">
<span *ngIf="showSad || h?.emotion != 'sad'">
<option [ngValue]="h">{{h.name}} ({{h?.emotion}})</option>
</span>
</span>
@ -147,7 +147,7 @@
<!-- #docregion select-ngcontainer -->
<select [(ngModel)]="hero">
<ng-container *ngFor="let h of heroes">
<ng-container *ngIf="showSad || h?.emotion !== 'sad'">
<ng-container *ngIf="showSad || h?.emotion != 'sad'">
<option [ngValue]="h">{{h.name}} ({{h?.emotion}})</option>
</ng-container>
</ng-container>

View File

@ -6,15 +6,14 @@ import { heroes } from './hero';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
heroes = heroes;
hero = this.heroes[0];
heroTraits = ['honest', 'brave', 'considerate'];
heroTraits = [ 'honest', 'brave', 'considerate' ];
// flags for the table
attrDirs = true;
strucDirs = true;
divNgIf = false;

View File

@ -1,9 +1,9 @@
// #docregion
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { AppComponent } from './app.component';
import { ContentComponent } from './content.component';
import { heroComponents } from './hero.components';

View File

@ -1,6 +1,5 @@
// #docregion
import { Component, Input } from '@angular/core';
import { Hero } from './hero';
@Component({
@ -34,15 +33,11 @@ export class ConfusedHeroComponent {
export class UnknownHeroComponent {
@Input() hero: Hero;
get message() {
return this.hero && this.hero.name
? `${this.hero.name} is strange and mysterious.`
: 'Are you feeling indecisive?';
return this.hero && this.hero.name ?
`${this.hero.name} is strange and mysterious.` :
'Are you feeling indecisive?';
}
}
export const heroComponents = [
HappyHeroComponent,
SadHeroComponent,
ConfusedHeroComponent,
UnknownHeroComponent
];
export const heroComponents =
[ HappyHeroComponent, SadHeroComponent, ConfusedHeroComponent, UnknownHeroComponent ];

View File

@ -6,8 +6,8 @@ export class Hero {
}
export const heroes: Hero[] = [
{ id: 1, name: 'Mr. Nice', emotion: 'happy' },
{ id: 2, name: 'Narco', emotion: 'sad' },
{ id: 1, name: 'Mr. Nice', emotion: 'happy'},
{ id: 2, name: 'Narco', emotion: 'sad' },
{ id: 3, name: 'Windstorm', emotion: 'confused' },
{ id: 4, name: 'Magneta' }
{ id: 4, name: 'Magneta'}
];

View File

@ -1,5 +1,7 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
/* App Root */
import { AppComponent } from './app.component';

View File

@ -15,7 +15,7 @@ function sequenceSubscriber(observer) {
if (idx === arr.length - 1) {
observer.complete();
} else {
doSequence(arr, ++idx);
doSequence(arr, idx++);
}
}, 1000);
}
@ -95,7 +95,7 @@ function multicastSequenceSubscriber() {
},
complete() {
// Notify all complete callbacks
observers.slice(0).forEach(obs => obs.complete());
observers.forEach(obs => obs.complete());
}
}, seq, 0);
}
@ -121,13 +121,13 @@ function doSequence(observer, arr, idx) {
if (idx === arr.length - 1) {
observer.complete();
} else {
doSequence(observer, arr, ++idx);
doSequence(observer, arr, idx++);
}
}, 1000);
}
// Create a new Observable that will deliver the above sequence
const multicastSequence = new Observable(multicastSequenceSubscriber());
const multicastSequence = new Observable(multicastSequenceSubscriber);
// Subscribe starts the clock, and begins to emit after 1 second
multicastSequence.subscribe({

View File

@ -1,21 +1,26 @@
// #docregion
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular//common/http';
import { AppComponent } from './app.component';
import { ExponentialStrengthPipe } from './exponential-strength.pipe';
import { FetchJsonPipe } from './fetch-json.pipe';
import { FlyingHeroesComponent, FlyingHeroesImpureComponent } from './flying-heroes.component';
import { FlyingHeroesImpurePipe, FlyingHeroesPipe } from './flying-heroes.pipe';
import {
FlyingHeroesComponent,
FlyingHeroesImpureComponent
} from './flying-heroes.component';
import { HeroAsyncMessageComponent } from './hero-async-message.component';
import { HeroBirthdayComponent } from './hero-birthday1.component';
import { HeroBirthday2Component } from './hero-birthday2.component';
import { HeroListComponent } from './hero-list.component';
import { PowerBoostCalculatorComponent } from './power-boost-calculator.component';
import { PowerBoosterComponent } from './power-booster.component';
import { PowerBoostCalculatorComponent } from './power-boost-calculator.component';
import {
FlyingHeroesPipe,
FlyingHeroesImpurePipe
} from './flying-heroes.pipe';
import { FetchJsonPipe } from './fetch-json.pipe';
import { ExponentialStrengthPipe } from './exponential-strength.pipe';
@NgModule({
imports: [
@ -38,6 +43,6 @@ import { PowerBoosterComponent } from './power-booster.component';
FetchJsonPipe,
ExponentialStrengthPipe
],
bootstrap: [AppComponent]
bootstrap: [ AppComponent ]
})
export class AppModule { }

View File

@ -1,14 +1,13 @@
// #docregion
import { HttpClient } from '@angular/common/http';
import { Pipe, PipeTransform } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// #docregion pipe-metadata
@Pipe({
name: 'fetch',
pure: false
})
// #enddocregion pipe-metadata
export class FetchJsonPipe implements PipeTransform {
export class FetchJsonPipe implements PipeTransform {
private cachedData: any = null;
private cachedUrl = '';
@ -18,7 +17,7 @@ export class FetchJsonPipe implements PipeTransform {
if (url !== this.cachedUrl) {
this.cachedData = null;
this.cachedUrl = url;
this.http.get(url).subscribe(result => this.cachedData = result);
this.http.get(url).subscribe( result => this.cachedData = result );
}
return this.cachedData;

View File

@ -0,0 +1,3 @@
[1030/162525.401:ERROR:process_reader_win.cc(123)] NtOpenThread: {Acceso denegado} Un proceso ha solicitado acceso a un objeto, pero no se le han concedido esos derechos de acceso. (0xc0000022)
[1030/162525.402:ERROR:exception_snapshot_win.cc(87)] thread ID 26896 not found in process
[1030/162525.402:WARNING:crash_report_exception_handler.cc(62)] ProcessSnapshotWin::Initialize failed

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
{
"description": "Angular Reactive Forms (final)",
"files":[
"src/styles.css",
"src/app/app.component.ts",
"src/app/app.component.html",
"src/app/app.component.css",
"src/app/app.module.ts",
"src/app/data-model.ts",
"src/app/hero.service.ts",
"src/app/hero-detail/hero-detail.component.html",
"src/app/hero-detail/hero-detail.component.ts",
"src/app/hero-detail/hero-detail.component.css",
"src/app/hero-list/hero-list.component.html",
"src/app/hero-list/hero-list.component.ts",
"src/app/hero-list/hero-list.component.css",
"src/main-final.ts",
"src/index-final.html"
],
"main": "src/index-final.html",
"tags": ["reactive", "forms"]
}

View File

@ -1,10 +1,4 @@
<!-- #docplaster -->
<h1>Reactive Forms</h1>
<!-- #docregion app-name-editor-->
<app-name-editor></app-name-editor>
<!-- #enddocregion app-name-editor-->
<!-- #docregion app-profile-editor -->
<app-profile-editor></app-profile-editor>
<!-- #enddocregion app-profile-editor -->
<div class="container">
<h1>Reactive Forms</h1>
<app-hero-detail></app-hero-detail>
</div>

View File

@ -1,17 +1,4 @@
<!-- #docplaster -->
<!-- #docregion app-name-editor -->
<h1>Reactive Forms</h1>
<!-- #enddocregion app-name-editor -->
<nav>
<a (click)="toggleEditor('name')">Name Editor</a>
<a (click)="toggleEditor('profile')">Profile Editor</a>
</nav>
<!-- #docregion app-name-editor -->
<app-name-editor *ngIf="showNameEditor"></app-name-editor>
<!-- #enddocregion app-name-editor -->
<!-- #docregion app-profile-editor -->
<app-profile-editor *ngIf="showProfileEditor"></app-profile-editor>
<!-- #enddocregion app-profile-editor -->
<div class="container">
<h1>Reactive Forms</h1>
<app-hero-list></app-hero-list>
</div>

View File

@ -1,27 +0,0 @@
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'app'`, async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app');
}));
it('should render title in a h1 tag', async(() => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to reactive-forms!');
}));
});

View File

@ -1,24 +1,9 @@
// #docregion
import { Component } from '@angular/core';
export type EditorType = 'name' | 'profile';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
editor: EditorType = 'name';
get showNameEditor() {
return this.editor === 'name';
}
get showProfileEditor() {
return this.editor === 'profile';
}
toggleEditor(type: EditorType) {
this.editor = type;
}
}
export class AppComponent { }

View File

@ -1,34 +1,45 @@
// #docplaster
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
// #docregion imports
import { ReactiveFormsModule } from '@angular/forms';
// #docregion
// #docregion v1
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms'; // <-- #1 import module
// #enddocregion imports
import { AppComponent } from './app.component';
import { NameEditorComponent } from './name-editor/name-editor.component';
import { ProfileEditorComponent } from './profile-editor/profile-editor.component';
import { AppComponent } from './app.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
// #enddocregion v1
// #docregion hero-service-list
// add JavaScript imports
import { HeroListComponent } from './hero-list/hero-list.component';
import { HeroService } from './hero.service';
// #docregion v1
// #docregion imports
@NgModule({
// #enddocregion imports
declarations: [
AppComponent,
NameEditorComponent,
ProfileEditorComponent
HeroDetailComponent,
// #enddocregion v1
HeroListComponent // <--declare HeroListComponent
// #docregion v1
],
// #docregion imports
// #enddocregion hero-service-list
imports: [
// #enddocregion imports
BrowserModule,
// #docregion imports
// other imports ...
ReactiveFormsModule
ReactiveFormsModule // <-- #2 add to @NgModule imports
],
// #enddocregion imports
providers: [],
bootstrap: [AppComponent]
// #docregion imports
// #enddocregion v1
// export for the DemoModule
// #docregion hero-service-list
// ...
exports: [
AppComponent,
HeroDetailComponent,
HeroListComponent // <-- export HeroListComponent
],
providers: [ HeroService ], // <-- provide HeroService
// #enddocregion hero-service-list
// #docregion v1
bootstrap: [ AppComponent ]
})
export class AppModule { }
// #enddocregion imports
// #enddocregion v1

View File

@ -0,0 +1,40 @@
// #docregion
// #docregion model-classes
export class Hero {
id = 0;
name = '';
addresses: Address[];
}
export class Address {
street = '';
city = '';
state = '';
zip = '';
}
// #enddocregion model-classes
export const heroes: Hero[] = [
{
id: 1,
name: 'Whirlwind',
addresses: [
{street: '123 Main', city: 'Anywhere', state: 'CA', zip: '94801'},
{street: '456 Maple', city: 'Somewhere', state: 'VA', zip: '23226'},
]
},
{
id: 2,
name: 'Bombastic',
addresses: [
{street: '789 Elm', city: 'Smallville', state: 'OH', zip: '04501'},
]
},
{
id: 3,
name: 'Magneta',
addresses: [ ]
},
];
export const states = ['CA', 'MD', 'OH', 'VA'];

View File

@ -0,0 +1,40 @@
<div class="container">
<h1>Reactive Forms</h1>
<h4><i>Pick a demo:</i>
<select [selectedIndex]="demo - 1" (change)="selectDemo($event.target.selectedIndex)">
<option *ngFor="let demo of demos">{{demo}}</option>
</select>
</h4>
<hr>
<div class="demo">
<app-hero-list *ngIf="demo===final"></app-hero-list>
<app-hero-detail-1 *ngIf="demo===1"></app-hero-detail-1>
<app-hero-detail-2 *ngIf="demo===2"></app-hero-detail-2>
<app-hero-detail-3 *ngIf="demo===3"></app-hero-detail-3>
<app-hero-detail-4 *ngIf="demo===4"></app-hero-detail-4>
<app-hero-detail-5 *ngIf="demo===5"></app-hero-detail-5>
<div *ngIf="demo >= 6 && demo !== final" >
<h3 *ngIf="isLoading"><i>Loading heroes ... </i></h3>
<h3 *ngIf="!isLoading">Select a hero:</h3>
<nav>
<button (click)="getHeroes()" class="btn btn-primary">Refresh</button>
<a *ngFor="let hero of heroes | async" (click)="select(hero)">{{hero.name}}</a>
</nav>
<div *ngIf="selectedHero">
<hr>
<h2>Hero Detail</h2>
<h3>Editing: {{selectedHero.name}}</h3>
<app-hero-detail-6 [hero]=selectedHero *ngIf="demo===6"></app-hero-detail-6>
<app-hero-detail-7 [hero]=selectedHero *ngIf="demo===7"></app-hero-detail-7>
<app-hero-detail-8 [hero]=selectedHero *ngIf="demo===8"></app-hero-detail-8>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,49 @@
/* tslint:disable:member-ordering */
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { Hero } from './data-model';
import { HeroService } from './hero.service';
@Component({
selector: 'app-root',
templateUrl: './demo.component.html'
})
export class DemoComponent {
demos: string[] = [
'Just a FormControl',
'FormControl in a FormGroup',
'Simple FormBuilder group',
'Group with multiple controls',
'Nested FormBuilder group',
'PatchValue',
'SetValue',
'FormArray',
'Final'].map(n => n + ' Demo');
final = this.demos.length;
demo = this.final; // current demo
heroes: Observable<Hero[]>;
isLoading = false;
selectedHero: Hero;
constructor(private heroService: HeroService) { }
getHeroes() {
this.isLoading = true;
this.heroes = this.heroService.getHeroes().pipe(
finalize(() => this.isLoading = false)
);
this.selectedHero = undefined;
}
select(hero: Hero) { this.selectedHero = hero; }
selectDemo(demo: number) {
this.demo = demo + 1;
this.getHeroes();
}
}

View File

@ -0,0 +1,33 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppModule } from './app.module';
import { DemoComponent } from './demo.component';
import { HeroDetailComponent1 } from './hero-detail/hero-detail-1.component';
import { HeroDetailComponent2 } from './hero-detail/hero-detail-2.component';
import { HeroDetailComponent3 } from './hero-detail/hero-detail-3.component';
import { HeroDetailComponent4 } from './hero-detail/hero-detail-4.component';
import { HeroDetailComponent5 } from './hero-detail/hero-detail-5.component';
import { HeroDetailComponent6 } from './hero-detail/hero-detail-6.component';
import { HeroDetailComponent7 } from './hero-detail/hero-detail-7.component';
import { HeroDetailComponent8 } from './hero-detail/hero-detail-8.component';
@NgModule({
imports: [
BrowserModule,
ReactiveFormsModule,
AppModule,
],
declarations: [ DemoComponent,
HeroDetailComponent1,
HeroDetailComponent2,
HeroDetailComponent3,
HeroDetailComponent4,
HeroDetailComponent5,
HeroDetailComponent6,
HeroDetailComponent7,
HeroDetailComponent8],
bootstrap: [ DemoComponent ]
})
export class DemoModule { }

View File

@ -0,0 +1,8 @@
<!-- #docregion simple-control-->
<h2>Hero Detail</h2>
<h3><i>Just a FormControl</i></h3>
<label class="center-block">Name:
<input class="form-control" [formControl]="name">
</label>
<!-- #enddocregion simple-control-->

View File

@ -0,0 +1,15 @@
/* tslint:disable:component-class-suffix */
import { Component } from '@angular/core';
// #docregion import
import { FormControl } from '@angular/forms';
// #enddocregion import
@Component({
selector: 'app-hero-detail-1',
templateUrl: './hero-detail-1.component.html'
})
// #docregion v1
export class HeroDetailComponent1 {
name = new FormControl();
}

View File

@ -0,0 +1,18 @@
<!-- #docregion basic-form-->
<h2>Hero Detail</h2>
<h3><i>FormControl in a FormGroup</i></h3>
<form [formGroup]="heroForm">
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
</form>
<!-- #enddocregion basic-form-->
<!-- #docregion form-value-json -->
<p>Form value: {{ heroForm.value | json }}</p>
<!-- #enddocregion form-value-json -->

View File

@ -0,0 +1,17 @@
/* tslint:disable:component-class-suffix */
// #docregion imports
import { Component } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
// #enddocregion imports
@Component({
selector: 'app-hero-detail-2',
templateUrl: './hero-detail-2.component.html'
})
// #docregion v2
export class HeroDetailComponent2 {
heroForm = new FormGroup ({
name: new FormControl()
});
}
// #enddocregion v2

View File

@ -0,0 +1,16 @@
<!-- #docregion basic-form-->
<h2>Hero Detail</h2>
<h3><i>A FormGroup with a single FormControl using FormBuilder</i></h3>
<form [formGroup]="heroForm">
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
</form>
<!-- #enddocregion basic-form-->
<!-- #docregion form-value-json -->
<p>Form value: {{ heroForm.value | json }}</p>
<p>Form status: {{ heroForm.status | json }}</p>
<!-- #enddocregion form-value-json -->

View File

@ -0,0 +1,27 @@
/* tslint:disable:component-class-suffix */
// #docregion imports
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
// #enddocregion imports
@Component({
selector: 'app-hero-detail-3',
templateUrl: './hero-detail-3.component.html'
})
// #docregion v3
export class HeroDetailComponent3 {
heroForm: FormGroup; // <--- heroForm is of type FormGroup
constructor(private fb: FormBuilder) { // <--- inject FormBuilder
this.createForm();
}
createForm() {
// #docregion required
this.heroForm = this.fb.group({
name: ['', Validators.required ],
});
// #enddocregion required
}
}
// #enddocregion v3

View File

@ -0,0 +1,25 @@
/* tslint:disable:component-class-suffix */
// #docregion imports
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
// #enddocregion imports
@Component({
selector: 'app-hero-detail-3',
templateUrl: './hero-detail-3.component.html'
})
// #docregion v3a
export class HeroDetailComponent3 {
heroForm: FormGroup; // <--- heroForm is of type FormGroup
constructor(private fb: FormBuilder) { // <--- inject FormBuilder
this.createForm();
}
createForm() {
this.heroForm = this.fb.group({
name: '', // <--- the FormControl called "name"
});
}
}
// #enddocregion v3a

View File

@ -0,0 +1,46 @@
<!-- #docregion -->
<h2>Hero Detail</h2>
<h3><i>A FormGroup with multiple FormControls</i></h3>
<form [formGroup]="heroForm">
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="zip">
</label>
</div>
<div class="form-group radio">
<h4>Super power:</h4>
<label class="center-block"><input type="radio" formControlName="power" value="flight">Flight</label>
<label class="center-block"><input type="radio" formControlName="power" value="x-ray vision">X-ray vision</label>
<label class="center-block"><input type="radio" formControlName="power" value="strength">Strength</label>
</div>
<div class="checkbox">
<label class="center-block">
<input type="checkbox" formControlName="sidekick">I have a sidekick.
</label>
</div>
</form>
<p>Form value: {{ heroForm.value | json }}</p>

View File

@ -0,0 +1,34 @@
/* tslint:disable:component-class-suffix */
// #docregion imports
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { states } from '../data-model';
// #enddocregion imports
@Component({
selector: 'app-hero-detail-4',
templateUrl: './hero-detail-4.component.html'
})
// #docregion v4
export class HeroDetailComponent4 {
heroForm: FormGroup;
states = states;
constructor(private fb: FormBuilder) {
this.createForm();
}
createForm() {
this.heroForm = this.fb.group({
name: ['', Validators.required ],
street: '',
city: '',
state: '',
zip: '',
power: '',
sidekick: ''
});
}
}
// #enddocregion v4

View File

@ -0,0 +1,56 @@
<form [formGroup]="heroForm">
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<!-- #docregion add-group-->
<div formGroupName="address" class="well well-lg">
<h4>Secret Lair</h4>
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="zip">
</label>
</div>
</div>
<!-- #enddocregion add-group-->
<div class="form-group radio">
<h4>Super power:</h4>
<label class="center-block"><input type="radio" formControlName="power" value="flight">Flight</label>
<label class="center-block"><input type="radio" formControlName="power" value="x-ray vision">X-ray vision</label>
<label class="center-block"><input type="radio" formControlName="power" value="strength">Strength</label>
</div>
<div class="checkbox">
<label class="center-block">
<input type="checkbox" formControlName="sidekick">I have a sidekick.
</label>
</div>
</form>
<p>heroForm value: {{ heroForm.value | json}}</p>
<h4>Extra info for the curious:</h4>
<!-- #docregion inspect-value -->
<p>Name value: {{ heroForm.get('name').value }}</p>
<!-- #enddocregion inspect-value -->
<!-- #docregion inspect-child-control -->
<p>Street value: {{ heroForm.get('address.street').value}}</p>
<!-- #enddocregion inspect-child-control -->

View File

@ -0,0 +1,35 @@
/* tslint:disable:component-class-suffix */
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { states } from '../data-model';
@Component({
selector: 'app-hero-detail-5',
templateUrl: './hero-detail-5.component.html'
})
// #docregion v5
export class HeroDetailComponent5 {
heroForm: FormGroup;
states = states;
constructor(private fb: FormBuilder) {
this.createForm();
}
createForm() {
this.heroForm = this.fb.group({ // <-- the parent FormGroup
name: ['', Validators.required ],
address: this.fb.group({ // <-- the child FormGroup
street: '',
city: '',
state: '',
zip: ''
}),
power: '',
sidekick: ''
});
}
}
// #enddocregion v5

View File

@ -0,0 +1,46 @@
<!-- #docregion -->
<h2>Hero Detail</h2>
<h3><i>PatchValue to initialize a value</i></h3>
<form [formGroup]="heroForm">
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="zip">
</label>
</div>
<div class="form-group radio">
<h4>Super power:</h4>
<label class="center-block"><input type="radio" formControlName="power" value="flight">Flight</label>
<label class="center-block"><input type="radio" formControlName="power" value="x-ray vision">X-ray vision</label>
<label class="center-block"><input type="radio" formControlName="power" value="strength">Strength</label>
</div>
<div class="checkbox">
<label class="center-block">
<input type="checkbox" formControlName="sidekick">I have a sidekick.
</label>
</div>
</form>
<p>Form value: {{ heroForm.value | json }}</p>

View File

@ -0,0 +1,66 @@
/* tslint:disable:component-class-suffix */
// #docregion import-input
import { Component, Input, OnChanges } from '@angular/core';
// #enddocregion import-input
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
// #docregion import-hero
import { Hero, states } from '../data-model';
// #enddocregion import-hero
////////// 6 ////////////////////
@Component({
selector: 'app-hero-detail-6',
templateUrl: './hero-detail-5.component.html'
})
// #docregion v6
export class HeroDetailComponent6 implements OnChanges {
// #docregion hero
@Input() hero: Hero;
// #enddocregion hero
heroForm: FormGroup;
states = states;
constructor(private fb: FormBuilder) {
this.createForm();
}
createForm() {
// #docregion hero-form-model
this.heroForm = this.fb.group({
name: ['', Validators.required ],
address: this.fb.group({
street: '',
city: '',
state: '',
zip: ''
}),
power: '',
sidekick: ''
});
// #enddocregion hero-form-model
}
// #docregion patch-value-on-changes
ngOnChanges() { // <-- call rebuildForm in ngOnChanges
this.rebuildForm();
}
// #enddocregion patch-value-on-changes
// #docregion patch-value-rebuildform
rebuildForm() { // <-- wrap patchValue in rebuildForm
this.heroForm.reset();
// #docregion patch-value
this.heroForm.patchValue({
name: this.hero.name
});
// #enddocregion patch-value
}
// #enddocregion patch-value-rebuildform
}
// #enddocregion v6

View File

@ -0,0 +1,46 @@
<!-- #docregion -->
<h2>Hero Detail</h2>
<h3><i>A FormGroup with multiple FormControls</i></h3>
<form [formGroup]="heroForm">
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="zip">
</label>
</div>
<div class="form-group radio">
<h4>Super power:</h4>
<label class="center-block"><input type="radio" formControlName="power" value="flight">Flight</label>
<label class="center-block"><input type="radio" formControlName="power" value="x-ray vision">X-ray vision</label>
<label class="center-block"><input type="radio" formControlName="power" value="strength">Strength</label>
</div>
<div class="checkbox">
<label class="center-block">
<input type="checkbox" formControlName="sidekick">I have a sidekick.
</label>
</div>
</form>
<p>Form value: {{ heroForm.value | json }}</p>

View File

@ -0,0 +1,68 @@
/* tslint:disable:component-class-suffix */
// #docplaster
// #docregion imports
import { Component, Input, OnChanges } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
// #docregion import-address
import { Address, Hero, states } from '../data-model';
// #enddocregion import-address
// #enddocregion imports
@Component({
selector: 'app-hero-detail-7',
templateUrl: './hero-detail-5.component.html'
})
// #docregion v7
export class HeroDetailComponent7 implements OnChanges {
@Input() hero: Hero;
heroForm: FormGroup;
states = states;
constructor(private fb: FormBuilder) {
this.createForm();
}
createForm() {
// #docregion address-form-group
this.heroForm = this.fb.group({
name: ['', Validators.required ],
address: this.fb.group(new Address()), // <-- a FormGroup with a new address
power: '',
sidekick: ''
});
// #enddocregion address-form-group
}
// #docregion ngOnChanges
ngOnChanges() {
this.rebuildForm();
}
// #enddocregion ngOnChanges
// #docregion rebuildForm
rebuildForm() {
this.heroForm.reset({
name: this.hero.name,
// #docregion set-value-address
address: this.hero.addresses[0] || new Address()
// #enddocregion set-value-address
});
}
// #enddocregion rebuildForm
/* First version of rebuildForm */
rebuildForm1() {
// #docregion reset
this.heroForm.reset();
// #enddocregion reset
// #docregion set-value
this.heroForm.setValue({
name: this.hero.name,
address: this.hero.addresses[0] || new Address()
});
// #enddocregion set-value
}
}

View File

@ -0,0 +1,72 @@
<!-- #docplaster-->
<h3><i>Using FormArray to add groups</i></h3>
<form [formGroup]="heroForm">
<p>Form Changed: {{ heroForm.dirty }}</p>
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<!-- #docregion form-array-->
<!-- #docregion form-array-skeleton -->
<!-- #docregion form-array-name -->
<div formArrayName="secretLairs" class="well well-lg">
<!-- #enddocregion form-array-name -->
<div *ngFor="let address of secretLairs.controls; let i=index" [formGroupName]="i" >
<!-- The repeated address template -->
<!-- #enddocregion form-array-skeleton -->
<h4>Address #{{i + 1}}</h4>
<div style="margin-left: 1em;">
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="zip">
</label>
</div>
</div>
<br>
<!-- End of the repeated address template -->
<!-- #docregion form-array-skeleton -->
</div>
<!-- #enddocregion form-array-skeleton -->
<!-- #enddocregion form-array-->
<!-- #docregion add-lair -->
<button (click)="addLair()" type="button">Add a Secret Lair</button>
<!-- #enddocregion add-lair -->
<!-- #docregion form-array-->
<!-- #docregion form-array-skeleton -->
</div>
<!-- #enddocregion form-array-skeleton -->
<!-- #enddocregion form-array-->
<div class="form-group radio">
<h4>Super power:</h4>
<label class="center-block"><input type="radio" formControlName="power" value="flight">Flight</label>
<label class="center-block"><input type="radio" formControlName="power" value="x-ray vision">X-ray vision</label>
<label class="center-block"><input type="radio" formControlName="power" value="strength">Strength</label>
</div>
<div class="checkbox">
<label class="center-block">
<input type="checkbox" formControlName="sidekick">I have a sidekick.
</label>
</div>
</form>
<p>heroForm value: {{ heroForm.value | json}}</p>

View File

@ -0,0 +1,74 @@
/* tslint:disable:component-class-suffix */
// #docregion imports
import { Component, Input, OnChanges } from '@angular/core';
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Address, Hero, states } from '../data-model';
// #enddocregion imports
@Component({
selector: 'app-hero-detail-8',
templateUrl: './hero-detail-8.component.html'
})
// #docregion v8
export class HeroDetailComponent8 implements OnChanges {
@Input() hero: Hero;
heroForm: FormGroup;
states = states;
// #docregion ctor
constructor(private fb: FormBuilder) {
this.createForm();
this.logNameChange();
}
// #enddocregion ctor
createForm() {
// #docregion secretLairs-form-array
this.heroForm = this.fb.group({
name: ['', Validators.required ],
secretLairs: this.fb.array([]), // <-- secretLairs as an empty FormArray
power: '',
sidekick: ''
});
// #enddocregion secretLairs-form-array
}
logNameChange() {/* Coming soon */}
// #docregion onchanges
ngOnChanges() {
this.rebuildForm();
}
// #enddocregion onchanges
// #docregion rebuildform
rebuildForm() {
this.heroForm.reset({
name: this.hero.name
});
this.setAddresses(this.hero.addresses);
}
// #enddocregion rebuildform
// #docregion get-secret-lairs
get secretLairs(): FormArray {
return this.heroForm.get('secretLairs') as FormArray;
};
// #enddocregion get-secret-lairs
// #docregion set-addresses
setAddresses(addresses: Address[]) {
const addressFGs = addresses.map(address => this.fb.group(address));
const addressFormArray = this.fb.array(addressFGs);
this.heroForm.setControl('secretLairs', addressFormArray);
}
// #enddocregion set-addresses
// #docregion add-lair
addLair() {
this.secretLairs.push(this.fb.group(new Address()));
}
// #enddocregion add-lair
}

View File

@ -0,0 +1,73 @@
<!-- #docplaster -->
<!-- #docregion -->
<!-- #docregion buttons -->
<form [formGroup]="heroForm" (ngSubmit)="onSubmit()">
<div style="margin-bottom: 1em">
<button type="submit"
[disabled]="heroForm.pristine" class="btn btn-success">Save</button> &nbsp;
<button type="button" (click)="revert()"
[disabled]="heroForm.pristine" class="btn btn-danger">Revert</button>
</div>
<!-- Hero Detail Controls -->
<!-- #enddocregion buttons -->
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div formArrayName="secretLairs" class="well well-lg">
<div *ngFor="let address of secretLairs.controls; let i=index" [formGroupName]="i" >
<!-- The repeated address template -->
<h4>Address #{{i + 1}}</h4>
<div style="margin-left: 1em;">
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="zip">
</label>
</div>
</div>
<br>
<!-- End of the repeated address template -->
</div>
<button (click)="addLair()" type="button">Add a Secret Lair</button>
</div>
<!-- #docregion buttons -->
<div class="form-group radio">
<h4>Super power:</h4>
<label class="center-block"><input type="radio" formControlName="power" value="flight">Flight</label>
<label class="center-block"><input type="radio" formControlName="power" value="x-ray vision">X-ray vision</label>
<label class="center-block"><input type="radio" formControlName="power" value="strength">Strength</label>
</div>
<div class="checkbox">
<label class="center-block">
<input type="checkbox" formControlName="sidekick">I have a sidekick.
</label>
</div>
</form>
<!-- #enddocregion buttons -->
<p>heroForm value: {{ heroForm.value | json}}</p>
<!-- #docregion name-change-log -->
<h4>Name change log</h4>
<div *ngFor="let name of nameChangeLog">{{name}}</div>
<!-- #enddocregion name-change-log -->

View File

@ -0,0 +1,113 @@
// #docplaster
// #docregion
import { Component, Input, OnChanges } from '@angular/core';
import { FormArray, FormBuilder, FormGroup } from '@angular/forms';
import { Address, Hero, states } from '../data-model';
// #docregion import-service
import { HeroService } from '../hero.service';
// #enddocregion import-service
@Component({
selector: 'app-hero-detail',
templateUrl: './hero-detail.component.html',
styleUrls: ['./hero-detail.component.css']
})
// #docregion onchanges-implementation
export class HeroDetailComponent implements OnChanges {
// #enddocregion onchanges-implementation
@Input() hero: Hero;
heroForm: FormGroup;
// #docregion log-name-change
nameChangeLog: string[] = [];
// #enddocregion log-name-change
states = states;
// #docregion ctor
constructor(
private fb: FormBuilder,
private heroService: HeroService) {
this.createForm();
this.logNameChange();
}
// #enddocregion ctor
createForm() {
this.heroForm = this.fb.group({
name: '',
secretLairs: this.fb.array([]),
power: '',
sidekick: ''
});
}
ngOnChanges() {
this.rebuildForm();
}
rebuildForm() {
this.heroForm.reset({
name: this.hero.name
});
this.setAddresses(this.hero.addresses);
}
get secretLairs(): FormArray {
return this.heroForm.get('secretLairs') as FormArray;
};
setAddresses(addresses: Address[]) {
const addressFGs = addresses.map(address => this.fb.group(address));
const addressFormArray = this.fb.array(addressFGs);
this.heroForm.setControl('secretLairs', addressFormArray);
}
addLair() {
this.secretLairs.push(this.fb.group(new Address()));
}
// #docregion on-submit
onSubmit() {
this.hero = this.prepareSaveHero();
this.heroService.updateHero(this.hero).subscribe(/* error handling */);
this.rebuildForm();
}
// #enddocregion on-submit
// #docregion prepare-save-hero
prepareSaveHero(): Hero {
const formModel = this.heroForm.value;
// deep copy of form model lairs
const secretLairsDeepCopy: Address[] = formModel.secretLairs.map(
(address: Address) => Object.assign({}, address)
);
// return new `Hero` object containing a combination of original hero value(s)
// and deep copies of changed form model values
const saveHero: Hero = {
id: this.hero.id,
name: formModel.name as string,
// addresses: formModel.secretLairs // <-- bad!
addresses: secretLairsDeepCopy
};
return saveHero;
}
// #enddocregion prepare-save-hero
// #docregion revert
revert() { this.rebuildForm(); }
// #enddocregion revert
// #docregion log-name-change
logNameChange() {
const nameControl = this.heroForm.get('name');
nameControl.valueChanges.forEach(
(value: string) => this.nameChangeLog.push(value)
);
}
// #enddocregion log-name-change
}

View File

@ -0,0 +1,8 @@
<!-- #docregion -->
<nav>
<a *ngFor="let hero of heroes | async" (click)="select(hero)">{{hero.name}}</a>
</nav>
<div *ngIf="selectedHero">
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
</div>

View File

@ -0,0 +1,17 @@
<!-- #docregion -->
<h3 *ngIf="isLoading"><i>Loading heroes ... </i></h3>
<h3 *ngIf="!isLoading">Select a hero:</h3>
<nav>
<button (click)="getHeroes()" class="btn btn-primary">Refresh</button>
<a *ngFor="let hero of heroes | async" (click)="select(hero)">{{hero.name}}</a>
</nav>
<div *ngIf="selectedHero">
<hr>
<h2>Hero Detail</h2>
<h3>Editing: {{selectedHero.name}}</h3>
<!-- #docregion hero-binding -->
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
<!-- #enddocregion hero-binding -->
</div>

View File

@ -0,0 +1,32 @@
// #docregion
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { Hero } from '../data-model';
import { HeroService } from '../hero.service';
@Component({
selector: 'app-hero-list',
templateUrl: './hero-list.component.html',
styleUrls: ['./hero-list.component.css']
})
export class HeroListComponent implements OnInit {
heroes: Observable<Hero[]>;
isLoading = false;
selectedHero: Hero;
constructor(private heroService: HeroService) { }
ngOnInit() { this.getHeroes(); }
getHeroes() {
this.isLoading = true;
this.heroes = this.heroService.getHeroes()
// TODO: error handling
.pipe(finalize(() => this.isLoading = false));
this.selectedHero = undefined;
}
select(hero: Hero) { this.selectedHero = hero; }
}

View File

@ -0,0 +1,25 @@
// #docregion
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';
import { Hero, heroes } from './data-model';
@Injectable()
export class HeroService {
delayMs = 500;
// Fake server get; assume nothing can go wrong
getHeroes(): Observable<Hero[]> {
return of(heroes).pipe(delay(this.delayMs)); // simulate latency with delay
}
// Fake server update; assume nothing can go wrong
updateHero(hero: Hero): Observable<Hero> {
const oldHero = heroes.find(h => h.id === hero.id);
const newHero = Object.assign(oldHero, hero); // Demo: mutate cached hero
return of(newHero).pipe(delay(this.delayMs)); // simulate latency with delay
}
}

View File

@ -1,19 +0,0 @@
:host {
display: flex;
flex-direction: column;
padding-top: 24px;
}
label {
display: block;
width: 6em;
margin: .5em 0;
color: #607D8B;
font-weight: bold;
}
input {
height: 2em;
font-size: 1em;
padding-left: .4em;
}

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