diff --git a/.circleci/bazel.rc b/.circleci/bazel.rc new file mode 100644 index 0000000000..921c6293cf --- /dev/null +++ b/.circleci/bazel.rc @@ -0,0 +1,25 @@ +# These options are enabled when running on CI +# We do this by copying this file to /etc/bazel.bazelrc at the start of the build. +# See remote cache documentation in /docs/BAZEL.md + +# Don't be spammy in the logs +build --noshow_progress + +# Don't run manual tests +test --test_tag_filters=-manual + +# Enable experimental CircleCI bazel remote cache proxy +# See remote cache documentation in /docs/BAZEL.md +build --experimental_remote_spawn_cache --remote_rest_cache=http://localhost:7643 + +# Prevent unstable environment variables from tainting cache keys +build --experimental_strict_action_env + +# Workaround https://github.com/bazelbuild/bazel/issues/3645 +# Bazel doesn't calculate the memory ceiling correctly when running under Docker. +# Limit Bazel to consuming resources that fit in CircleCI "medium" class which is the default: +# https://circleci.com/docs/2.0/configuration-reference/#resource_class +build --local_resources=3072,2.0,1.0 + +# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309 +test --flaky_test_attempts=2 diff --git a/.circleci/config.yml b/.circleci/config.yml index 0c08ea1b8b..a2d8f0dbf1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,8 +12,15 @@ ## 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.0.8 -var_2: &cache_key angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.0.8 +var_1: &docker_image angular/ngcontainer:0.1.0 +var_2: &cache_key angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.1.0 + +# See remote cache documentation in /docs/BAZEL.md +var_3: &setup-bazel-remote-cache + run: + name: Start up bazel remote cache proxy + command: ~/bazel-remote-proxy -backend circleci:// + background: true # Settings common to each job anchor_1: &job_defaults @@ -34,10 +41,15 @@ jobs: steps: - checkout: <<: *post_checkout - # Check BUILD.bazel formatting before we have a node_modules directory - # Then we don't need any exclude pattern to avoid checking those files - - run: 'buildifier -mode=check $(find . -type f \( -name BUILD.bazel -or -name BUILD \)) || - (echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)' + # 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: 'yarn buildifier -mode=check || + (echo -e "\nBUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)' + - run: 'yarn skylint || + (echo -e "\n.bzl files have lint errors. Please run ''yarn skylint''"; exit 1)' - restore_cache: key: *cache_key @@ -51,15 +63,29 @@ jobs: steps: - 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 info release - 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 a build command to finish before running the first test # See https://github.com/bazelbuild/bazel/issues/4257 - - run: bazel query --output=label '//packages/... union @angular//...' | xargs bazel test --config=ci + - run: bazel query --output=label '//modules/... union //packages/... union //tools/...' | xargs bazel test + + # 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. + - store_artifacts: + path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js + destination: packages/core/test/bundling/hello_world/bundle.min.js + - store_artifacts: + path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js.brotli + destination: packages/core/test/bundling/hello_world/bundle.min.js.brotli - save_cache: key: *cache_key diff --git a/.circleci/setup_cache.sh b/.circleci/setup_cache.sh new file mode 100755 index 0000000000..232596df4a --- /dev/null +++ b/.circleci/setup_cache.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# Install bazel remote cache proxy +# This is temporary until the feature is no longer experimental on CircleCI. +# See remote cache documentation in /docs/BAZEL.md + +set -u -e + +readonly DOWNLOAD_URL="https://5-116431813-gh.circle-artifacts.com/0/pkg/bazel-remote-proxy-$(uname -s)_$(uname -m)" + +curl --fail -o ~/bazel-remote-proxy "$DOWNLOAD_URL" +chmod +x ~/bazel-remote-proxy diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 3c9805e95a..b72a3a45f6 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -25,7 +25,7 @@ ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION. ## Minimal reproduction of the problem with instructions ## What is the motivation / use case for changing the behavior? diff --git a/.github/angular-robot.yml b/.github/angular-robot.yml new file mode 100644 index 0000000000..40eda24d69 --- /dev/null +++ b/.github/angular-robot.yml @@ -0,0 +1,102 @@ +# Configuration for angular-robot + +# options for the merge plugin +merge: + # the status will be added to your pull requests + status: + # set to true to disable + disabled: false + # the name of the status + context: "ci/angular: merge status" + # text to show when all checks pass + successText: "All checks passed!" + # text to show when some checks are failing + failureText: "The following checks are failing:" + + # the g3 status will be added to your pull requests if they include files that match the patterns + g3Status: + # set to true to disable + disabled: false + # the name of the status + context: "google3" + # text to show when the status is pending + pendingDesc: "Googler: test this change in google3 http://go/angular-g3sync" + # text to show when the status is success + successDesc: "Does not affect google3" + # list of patterns to check for the files changed by the PR + # this list must be manually kept in sync with google3/third_party/javascript/angular2/copy.bara.sky + include: + - "BUILD.bazel" + - "LICENSE" + - "WORKSPACE" + - "modules/**" + - "packages/**" + # list of patterns to ignore for the files changed by the PR + exclude: + - "packages/language-service/**" + - "**/.gitignore" + - "**/.gitkeep" + + # comment that will be added to a PR when there is a conflict, leave empty or set to false to disable + mergeConflictComment: "Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges. +\nPlease help to unblock it by resolving these conflicts. Thanks!" + + # label to monitor + mergeLabel: "PR action: merge" + + # list of checks that will determine if the merge label can be added + checks: + # whether the PR shouldn't have a conflict with the base branch + noConflict: true + # list of labels that a PR needs to have, checked with a regexp (e.g. "PR target:" will work for the label "PR target: master") + requiredLabels: + - "PR target: *" + - "cla: yes" + + # list of labels that a PR shouldn't have, checked after the required labels with a regexp + forbiddenLabels: + - "PR target: TBD" + - "PR action: cleanup" + - "PR action: review" + - "PR state: blocked" + - "cla: no" + + # list of PR statuses that need to be successful + requiredStatuses: + - "continuous-integration/travis-ci/pr" + - "code-review/pullapprove" + - "ci/circleci: build" + - "ci/circleci: lint" + + # the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable + # {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option + # {{PLACEHOLDER}} will be replaced by the list of failing checks + mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label, but the following checks are still failing: +\n{{PLACEHOLDER}} +\n +\n**If you want your PR to be merged, it has to pass all the CI checks.** +\n +\nIf you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help." + +# options for the triage plugin +triage: + # number of the milestone to apply when the issue has not been triaged yet + needsTriageMilestone: 83, + # number of the milestone to apply when the issue is triaged + defaultMilestone: 82, + # arrays of labels that determine if an issue is triaged + triagedLabels: + - + - "type: bug/fix" + - "severity*" + - "freq*" + - "comp: *" + - + - "type: feature" + - "comp: *" + - + - "type: refactor" + - "comp: *" + - + - "type: RFC / Discussion / question" + - "comp: *" diff --git a/.pullapprove.yml b/.pullapprove.yml index 6d4e0aef5f..235010747c 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -10,11 +10,11 @@ # brocco - Mike Brocchi # chuckjaz - Chuck Jazdzewski # filipesilva - Filipe Silva -# Foxandxss - Jesús Rodríguez # gkalpak - George Kalpakas # hansl - Hans Larsen # IgorMinar - Igor Minar # jasonaden - Jason Aden +# kapunahelewong - Kapunahele Wong # kara - Kara Erickson # matsko - Matias Niemelä # mhevery - Misko Hevery @@ -44,6 +44,7 @@ groups: all: users: all required: 1 + rejection_value: -999 # In this group, your self-approval does not count author_approval: auto: false @@ -91,7 +92,8 @@ groups: users: - alexeagle #primary - chuckjaz - - IgorMinar + - IgorMinar #fallback + - mhevery - vikerman #fallback build-and-ci: @@ -127,8 +129,9 @@ groups: files: - "packages/core/*" users: - - chuckjaz #primary - - mhevery + - mhevery #primary + - chuckjaz + - kara - vicb - IgorMinar #fallback @@ -139,7 +142,6 @@ groups: - "packages/platform-browser/animations/*" users: - matsko #primary - - chuckjaz #fallback - mhevery #fallback - IgorMinar #fallback @@ -171,6 +173,7 @@ groups: - hansl - filipesilva #fallback - brocco #fallback + - IgorMinar #fallback compiler-cli: conditions: @@ -204,6 +207,12 @@ groups: conditions: files: - "packages/forms/*" + - "aio/content/guide/forms.md" + - "aio/content/guide/form-validation.md" + - "aio/content/guide/reactive-forms.md" + - "aio/content/examples/forms/*" + - "aio/content/examples/form-validation/*" + - "aio/content/examples/reactive-forms/*" users: - kara #primary - tinayuangao #secondary @@ -216,9 +225,8 @@ groups: - "packages/common/http/*" - "packages/http/*" users: - - vikerman #primary - - alxhub - - IgorMinar #fallback + - alxhub #primary + - IgorMinar - mhevery #fallback language-service: @@ -237,7 +245,7 @@ groups: files: - "packages/router/*" users: - - jasonaden + - jasonaden #primary - vicb - IgorMinar #fallback - mhevery #fallback @@ -268,8 +276,7 @@ groups: - "packages/platform-server/*" users: - vikerman #primary - # needs secondary - - alxhub + - alxhub #secondary - vicb - IgorMinar #fallback - mhevery #fallback @@ -327,11 +334,11 @@ groups: - "aio/content/navigation.json" - "aio/content/license.md" users: + - kapunahelewong - stephenfluin - - Foxandxss - petebacondarwin - gkalpak - - IgorMinar #fallback + - IgorMinar - mhevery #fallback angular.io-marketing: @@ -345,5 +352,5 @@ groups: - stephenfluin - petebacondarwin - gkalpak - - IgorMinar #fallback + - IgorMinar - mhevery #fallback diff --git a/.travis.yml b/.travis.yml index 4326581272..6309b272b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,7 +56,6 @@ env: - CI_MODE=aio - CI_MODE=aio_e2e AIO_SHARD=0 - CI_MODE=aio_e2e AIO_SHARD=1 - - CI_MODE=bazel matrix: fast_finish: true diff --git a/BUILD.bazel b/BUILD.bazel index bea8d6fcf0..3ae5672cf0 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -24,9 +24,7 @@ filegroup( "typescript", "zone.js", "tsutils", - "@types/jasmine", - "@types/node", - "@types/source-map", + "@types", "tsickle", "hammerjs", "protobufjs", @@ -34,6 +32,7 @@ filegroup( "reflect-metadata", "source-map-support", "minimist", + "tslib", ] for ext in [ "*.js", "*.json", diff --git a/CHANGELOG.md b/CHANGELOG.md index 4102638a18..983b2ccd65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,309 @@ + +# [6.0.0-beta.5](https://github.com/angular/angular/compare/6.0.0-beta.4...6.0.0-beta.5) (2018-02-22) + +### Bug Fixes + +* **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)) +* **common:** correct mapping of Observable methods ([#20518](https://github.com/angular/angular/issues/20518)) ([2639b4b](https://github.com/angular/angular/commit/2639b4b)), closes [#20516](https://github.com/angular/angular/issues/20516) +* **common:** then and else template might be set to null ([#22298](https://github.com/angular/angular/issues/22298)) ([8115edc](https://github.com/angular/angular/commit/8115edc)) +* **compiler-cli:** add missing entry point to package, update tsickle ([#22295](https://github.com/angular/angular/issues/22295)) ([28ac244](https://github.com/angular/angular/commit/28ac244)) +* **core:** properly handle function without prototype in reflector ([#22284](https://github.com/angular/angular/issues/22284)) ([a7ebf5a](https://github.com/angular/angular/commit/a7ebf5a)), closes [#19978](https://github.com/angular/angular/issues/19978) +* **core:** require factory to be provided for shakeable InjectionToken ([#22207](https://github.com/angular/angular/issues/22207)) ([f755db7](https://github.com/angular/angular/commit/f755db7)), closes [#22205](https://github.com/angular/angular/issues/22205) +* **forms:** set state before emitting a value from ngModelChange ([#21514](https://github.com/angular/angular/issues/21514)) ([3e6a86f](https://github.com/angular/angular/commit/3e6a86f)), closes [#21513](https://github.com/angular/angular/issues/21513) +* **core:** set `preserveWhitespaces` to false by default ([#22046](https://github.com/angular/angular/issues/22046)) ([f1a0632](https://github.com/angular/angular/commit/f1a0632)), closes [#22027](https://github.com/angular/angular/issues/22027) + +### Features + +* **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) +* **compiler-cli:** Check unvalidated combination of ngc and TypeScript ([#22293](https://github.com/angular/angular/issues/22293)) ([3ceee99](https://github.com/angular/angular/commit/3ceee99)), closes [#20669](https://github.com/angular/angular/issues/20669) +* **core:** support metadata reflection for native class types ([#22356](https://github.com/angular/angular/issues/22356)) ([5c89d6b](https://github.com/angular/angular/commit/5c89d6b)), closes [#21731](https://github.com/angular/angular/issues/21731) +* **platform-browser:** do not throw error when Hammer.js not loaded ([#22257](https://github.com/angular/angular/issues/22257)) ([991300b](https://github.com/angular/angular/commit/991300b)), closes [#16992](https://github.com/angular/angular/issues/16992) +* **platform-browser:** fix [#19604](https://github.com/angular/angular/issues/19604), can config hammerOptions ([#21979](https://github.com/angular/angular/issues/21979)) ([1d571b2](https://github.com/angular/angular/commit/1d571b2)) + +### 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). To detect if an animation event is reporting a disabled +animation then the `event.disabled` property can be used instead. + +* **forms:** ngModelChange is now emitted after the value/validity is updated on its control. + +Previously, ngModelChange was emitted before its underlying control was updated. +This was fine if you passed through the value directly through the $event keyword, e.g. + +``` + + +onChange(value) { + console.log(value); // would log updated value +} +``` + +However, if you had a handler for the ngModelChange event that checked the value through the control, +you would get the old value rather than the updated value. e.g: + +``` + + +onChange(ngModel: NgModel) { + console.log(ngModel.value); // would log old value, not updated value +} +``` + +Now the value and validity will be updated before the ngModelChange event is emitted, +so the same setup will log the updated value. + +``` +onChange(ngModel: NgModel) { + console.log(ngModel.value); // will log updated value +} +``` + +We think this order will be less confusing when the control is checked directly. +You will only need to update your app if it has relied on this bug to keep track of the old control value. +If that is the case, you should be able to track the old value directly by saving it on your component. + + +## [5.2.6](https://github.com/angular/angular/compare/5.2.5...5.2.6) (2018-02-22) + +### Bug Fixes + +* **common:** correct mapping of Observable methods ([#20518](https://github.com/angular/angular/issues/20518)) ([ce5e8fa](https://github.com/angular/angular/commit/ce5e8fa)), closes [#20516](https://github.com/angular/angular/issues/20516) +* **common:** then and else template might be set to null ([#22298](https://github.com/angular/angular/issues/22298)) ([af6a056](https://github.com/angular/angular/commit/af6a056)) +* **compiler-cli:** add missing entry point to package, update tsickle ([#22295](https://github.com/angular/angular/issues/22295)) ([c5418c7](https://github.com/angular/angular/commit/c5418c7)) +* **core:** properly handle function without prototype in reflector ([#22284](https://github.com/angular/angular/issues/22284)) ([5ec38f2](https://github.com/angular/angular/commit/5ec38f2)), closes [#19978](https://github.com/angular/angular/issues/19978) +* **core:** support metadata reflection for native class types ([#22356](https://github.com/angular/angular/issues/22356)) ([ee91de9](https://github.com/angular/angular/commit/ee91de9)), closes [#21731](https://github.com/angular/angular/issues/21731) + + +# [6.0.0-beta.4](https://github.com/angular/angular/compare/6.0.0-beta.3...6.0.0-beta.4) (2018-02-14) + +### Bug Fixes + +* **bazel:** allow TS to read ambient typings ([#21876](https://github.com/angular/angular/issues/21876)) ([b081dfe](https://github.com/angular/angular/commit/b081dfe)), closes [#21872](https://github.com/angular/angular/issues/21872) +* **bazel:** improve error message for missing assets ([#22096](https://github.com/angular/angular/issues/22096)) ([dcf64a0](https://github.com/angular/angular/commit/dcf64a0)), closes [#22095](https://github.com/angular/angular/issues/22095) +* **common:** add locale currency values ([#21783](https://github.com/angular/angular/issues/21783)) ([420cc7a](https://github.com/angular/angular/commit/420cc7a)), closes [#20385](https://github.com/angular/angular/issues/20385) +* **common:** round currencies based on decimal digits in `CurrencyPipe` ([#21783](https://github.com/angular/angular/issues/21783)) ([44154e7](https://github.com/angular/angular/commit/44154e7)), closes [#10189](https://github.com/angular/angular/issues/10189) +* **common:** weaken AsyncPipe transform signature ([#22169](https://github.com/angular/angular/issues/22169)) ([be59c3a](https://github.com/angular/angular/commit/be59c3a)) +* **compiler:** make unary plus operator consistent to JavaScript ([#22154](https://github.com/angular/angular/issues/22154)) ([72f8abd](https://github.com/angular/angular/commit/72f8abd)), closes [#22089](https://github.com/angular/angular/issues/22089) +* **core:** add stacktrace in log when error during cleanup component in TestBed ([#22162](https://github.com/angular/angular/issues/22162)) ([16d1700](https://github.com/angular/angular/commit/16d1700)) +* **core:** ensure initial value of QueryList length ([#21980](https://github.com/angular/angular/issues/21980)) ([#21982](https://github.com/angular/angular/issues/21982)) ([e56de10](https://github.com/angular/angular/commit/e56de10)), closes [#21980](https://github.com/angular/angular/issues/21980) +* **core:** use appropriate inert document strategy for Firefox & Safari ([#17019](https://github.com/angular/angular/issues/17019)) ([a751649](https://github.com/angular/angular/commit/a751649)) +* **forms:** make Validators.email support optional controls ([#20869](https://github.com/angular/angular/issues/20869)) ([140e7c0](https://github.com/angular/angular/commit/140e7c0)) +* **forms:** prevent event emission on enable/disable when emitEvent is false ([#12366](https://github.com/angular/angular/issues/12366)) ([#21018](https://github.com/angular/angular/issues/21018)) ([0bcfae7](https://github.com/angular/angular/commit/0bcfae7)) +* **forms:** set state before emitting a value from ngModelChange ([#21514](https://github.com/angular/angular/issues/21514)) ([9744a1c](https://github.com/angular/angular/commit/9744a1c)), closes [#21513](https://github.com/angular/angular/issues/21513) +* **language-service:** correct instructions to install the language service ([#22000](https://github.com/angular/angular/issues/22000)) ([b37cee3](https://github.com/angular/angular/commit/b37cee3)) +* **platform-browser:** add @Injectable where it was missing ([#22005](https://github.com/angular/angular/issues/22005)) ([0a1a397](https://github.com/angular/angular/commit/0a1a397)) +* **platform-browser:** support 0/false/null values in transfer_state ([#22179](https://github.com/angular/angular/issues/22179)) ([6435ecd](https://github.com/angular/angular/commit/6435ecd)) + + +### Features + +* **bazel:** allow explicit specification of factories ([#22003](https://github.com/angular/angular/issues/22003)) ([e442881](https://github.com/angular/angular/commit/e442881)) +* **compiler:** mark @NgModules in provider lists for identification at runtime ([#22005](https://github.com/angular/angular/issues/22005)) ([2d5e7d1](https://github.com/angular/angular/commit/2d5e7d1)) +* **forms:** multiple validators for array method ([#20766](https://github.com/angular/angular/issues/20766)) ([941e88f](https://github.com/angular/angular/commit/941e88f)), closes [#20665](https://github.com/angular/angular/issues/20665) +* change @Injectable() to support tree-shakeable tokens ([#22005](https://github.com/angular/angular/issues/22005)) ([235a235](https://github.com/angular/angular/commit/235a235)) + + +## [5.2.5](https://github.com/angular/angular/compare/5.2.4...5.2.5) (2018-02-14) + +### Bug Fixes + +* **aio:** update Firebase redirects and SW routes ([#21763](https://github.com/angular/angular/pull/21763)) ([#22104](https://github.com/angular/angular/pull/22104)) ([15ff7ba](https://github.com/angular/angular/commit/15ff7ba)), closes [#21377](https://github.com/angular/angular/issues/21377) +* **bazel:** allow TS to read ambient typings ([#21876](https://github.com/angular/angular/issues/21876)) ([d57fd0b](https://github.com/angular/angular/commit/d57fd0b)), closes [#21872](https://github.com/angular/angular/issues/21872) +* **bazel:** improve error message for missing assets ([#22096](https://github.com/angular/angular/issues/22096)) ([c5ec8d9](https://github.com/angular/angular/commit/c5ec8d9)), closes [#22095](https://github.com/angular/angular/issues/22095) +* **common:** weaken AsyncPipe transform signature ([#22169](https://github.com/angular/angular/issues/22169)) ([c6bdc83](https://github.com/angular/angular/commit/c6bdc83)) +* **compiler:** make unary plus operator consistent to JavaScript ([#22154](https://github.com/angular/angular/issues/22154)) ([1b8ea10](https://github.com/angular/angular/commit/1b8ea10)), closes [#22089](https://github.com/angular/angular/issues/22089) +* **core:** add stacktrace in log when error during cleanup component in TestBed ([#22162](https://github.com/angular/angular/issues/22162)) ([c4f841f](https://github.com/angular/angular/commit/c4f841f)) +* **core:** ensure initial value of QueryList length ([#21980](https://github.com/angular/angular/issues/21980)) ([#21982](https://github.com/angular/angular/issues/21982)) ([47b73fd](https://github.com/angular/angular/commit/47b73fd)), closes [#21980](https://github.com/angular/angular/issues/21980) +* **core:** use appropriate inert document strategy for Firefox & Safari ([#17019](https://github.com/angular/angular/issues/17019)) ([47b71d9](https://github.com/angular/angular/commit/47b71d9)) +* **forms:** prevent event emission on enable/disable when emitEvent is false ([#12366](https://github.com/angular/angular/issues/12366)) ([#21018](https://github.com/angular/angular/issues/21018)) ([56b9591](https://github.com/angular/angular/commit/56b9591)) +* **language-service:** correct instructions to install the language service ([#22000](https://github.com/angular/angular/issues/22000)) ([0b23573](https://github.com/angular/angular/commit/0b23573)) +* **platform-browser:** support 0/false/null values in transfer_state ([#22179](https://github.com/angular/angular/issues/22179)) ([da6ab91](https://github.com/angular/angular/commit/da6ab91)) + + +# [6.0.0-beta.3](https://github.com/angular/angular/compare/6.0.0-beta.2...6.0.0-beta.3) (2018-02-07) + +### Bug Fixes + +* **common:** don't convert null to a string when flushing a mock request ([#21417](https://github.com/angular/angular/issues/21417)) ([8b14488](https://github.com/angular/angular/commit/8b14488)), closes [#20744](https://github.com/angular/angular/issues/20744) +* **core:** fix [#20582](https://github.com/angular/angular/issues/20582), don't need to wrap zone in location change listener ([#20640](https://github.com/angular/angular/issues/20640)) ([f791e9f](https://github.com/angular/angular/commit/f791e9f)) +* **core:** fix proper propagation of subscriptions in EventEmitter ([#22016](https://github.com/angular/angular/issues/22016)) ([e81606c](https://github.com/angular/angular/commit/e81606c)), closes [#21999](https://github.com/angular/angular/issues/21999) +* **core:** should check Zone existance when scheduleMicroTask ([#20656](https://github.com/angular/angular/issues/20656)) ([3a86940](https://github.com/angular/angular/commit/3a86940)) +* **forms:** publish missing types ([#19941](https://github.com/angular/angular/issues/19941)) ([2707012](https://github.com/angular/angular/commit/2707012)) +* **ivy:** generate correct interpolations ([#21946](https://github.com/angular/angular/issues/21946)) ([3cc1d76](https://github.com/angular/angular/commit/3cc1d76)) +* **ivy:** generate lifecycle pattern ([#21865](https://github.com/angular/angular/issues/21865)) ([f816666](https://github.com/angular/angular/commit/f816666)) +* **ivy:** improve `bindV` perf and memory usage ([#21881](https://github.com/angular/angular/issues/21881)) ([0846784](https://github.com/angular/angular/commit/0846784)) +* **ivy:** remove unnecessary parameter of NgOnChangesFeature ([#21879](https://github.com/angular/angular/issues/21879)) ([65cf1ad](https://github.com/angular/angular/commit/65cf1ad)) + + +### Features + +* **compiler-cli:** reflect static methods added to classes in metadata ([#21926](https://github.com/angular/angular/issues/21926)) ([eb8ddd2](https://github.com/angular/angular/commit/eb8ddd2)) +* **ivy:** add canonical example of a pipe. ([#21834](https://github.com/angular/angular/issues/21834)) ([743d8bc](https://github.com/angular/angular/commit/743d8bc)) +* **ivy:** add support for attributes on ng-content nodes ([#21935](https://github.com/angular/angular/issues/21935)) ([1aa2947](https://github.com/angular/angular/commit/1aa2947)) +* **ivy:** memoize array literals in render3 ([#21973](https://github.com/angular/angular/issues/21973)) ([4d62be6](https://github.com/angular/angular/commit/4d62be6)) + + +### Performance Improvements + +* **ivy:** improve Uglify configuration in hello world integration test ([#21985](https://github.com/angular/angular/issues/21985)) ([7e51e52](https://github.com/angular/angular/commit/7e51e52)) + + + + +## [5.2.4](https://github.com/angular/angular/compare/5.2.3...5.2.4) (2018-02-07) + + +### Bug Fixes + +* **common:** don't convert null to a string when flushing a mock request ([#21417](https://github.com/angular/angular/issues/21417)) ([c4fb696](https://github.com/angular/angular/commit/c4fb696)), closes [#20744](https://github.com/angular/angular/issues/20744) +* **core:** fix [#20582](https://github.com/angular/angular/issues/20582), don't need to wrap zone in location change listener ([#22007](https://github.com/angular/angular/issues/22007)) ([ce51ea9](https://github.com/angular/angular/commit/ce51ea9)) +* **core:** fix proper propagation of subscriptions in EventEmitter ([#22016](https://github.com/angular/angular/issues/22016)) ([c6645e7](https://github.com/angular/angular/commit/c6645e7)), closes [#21999](https://github.com/angular/angular/issues/21999) +* **core:** should check Zone existance when scheduleMicroTask ([#20656](https://github.com/angular/angular/issues/20656)) ([aa9ba7f](https://github.com/angular/angular/commit/aa9ba7f)) + + + + +# [6.0.0-beta.2](https://github.com/angular/angular/compare/6.0.0-beta.1...6.0.0-beta.2) (2018-01-31) + + +### Features + +* **router:** add navigationSource and restoredState to NavigationStart event ([#21728](https://github.com/angular/angular/issues/21728)) ([c40ae7f](https://github.com/angular/angular/commit/c40ae7f)) +* **service-worker:** add helper script which will uninstall SW ([#21863](https://github.com/angular/angular/issues/21863)) ([b10540a](https://github.com/angular/angular/commit/b10540a)) + + + + +## [5.2.3](https://github.com/angular/angular/compare/5.2.2...5.2.3) (2018-01-31) + + +### Bug Fixes + +* **common:** allow HttpInterceptors to inject HttpClient ([#19809](https://github.com/angular/angular/issues/19809)) ([ed2b717](https://github.com/angular/angular/commit/ed2b717)), closes [#18224](https://github.com/angular/angular/issues/18224) +* **common:** generate closure-locale data file with exported plural functions ([#21873](https://github.com/angular/angular/issues/21873)) ([c2f5ed5](https://github.com/angular/angular/commit/c2f5ed5)), closes [#21870](https://github.com/angular/angular/issues/21870) +* **core:** fix retrieving the binding name when an expression changes ([#21814](https://github.com/angular/angular/issues/21814)) ([81d64d6](https://github.com/angular/angular/commit/81d64d6)), closes [#21735](https://github.com/angular/angular/issues/21735) [#21788](https://github.com/angular/angular/issues/21788) +* **forms:** allow FormBuilder to create controls with any formState type ([#20917](https://github.com/angular/angular/issues/20917)) ([56f3e18](https://github.com/angular/angular/commit/56f3e18)), closes [#20368](https://github.com/angular/angular/issues/20368) +* **forms:** inserting and removing controls should work in re-bound form arrays ([#21822](https://github.com/angular/angular/issues/21822)) ([fad99cc](https://github.com/angular/angular/commit/fad99cc)), closes [#21501](https://github.com/angular/angular/issues/21501) +* **language-service:** ensure correct paths are passed to TypeScript ([#21812](https://github.com/angular/angular/issues/21812)) ([250c8da](https://github.com/angular/angular/commit/250c8da)) +* **language-service:** spell diagnostics correctly ([#21812](https://github.com/angular/angular/issues/21812)) ([778e6e7](https://github.com/angular/angular/commit/778e6e7)) +* **router:** remove [@internal](https://github.com/internal) tag on ParamInheritanceType ([#21773](https://github.com/angular/angular/issues/21773)) ([35a0721](https://github.com/angular/angular/commit/35a0721)), closes [#21456](https://github.com/angular/angular/issues/21456) + + + + +# [6.0.0-beta.1](https://github.com/angular/angular/compare/6.0.0-beta.0...6.0.0-beta.1) (2018-01-25) + + +### Bug Fixes + +* **common:** A null value should remove the style on IE ([#21679](https://github.com/angular/angular/issues/21679)) ([7d49443](https://github.com/angular/angular/commit/7d49443)), closes [#21064](https://github.com/angular/angular/issues/21064) +* avoid triggering a cli bug ([#21611](https://github.com/angular/angular/issues/21611)) ([0eabd07](https://github.com/angular/angular/commit/0eabd07)) +* **common:** don't remove special characters when extracting CLDR data ([#21626](https://github.com/angular/angular/issues/21626)) ([135a282](https://github.com/angular/angular/commit/135a282)) +* **common:** extract plural function from i18n locale data files for TS 2.6 ([#21626](https://github.com/angular/angular/issues/21626)) ([97b18b2](https://github.com/angular/angular/commit/97b18b2)), closes [#21608](https://github.com/angular/angular/issues/21608) +* **common:** fallback to last defined value for named date and time formats ([#21299](https://github.com/angular/angular/issues/21299)) ([879756d](https://github.com/angular/angular/commit/879756d)), closes [#21282](https://github.com/angular/angular/issues/21282) +* **compiler:** add support for marker tags in xliff serializers ([#21250](https://github.com/angular/angular/issues/21250)) ([f74130c](https://github.com/angular/angular/commit/f74130c)), closes [#21078](https://github.com/angular/angular/issues/21078) +* **compiler:** Don't strip `/*# sourceURL ... */` ([#16088](https://github.com/angular/angular/issues/16088)) ([5f681f9](https://github.com/angular/angular/commit/5f681f9)) +* **compiler:** fix ICU select messages to use male/female/other ([#21713](https://github.com/angular/angular/issues/21713)) ([cb5090c](https://github.com/angular/angular/commit/cb5090c)) +* **compiler-cli:** do not fold errors past calls in the collector ([#21708](https://github.com/angular/angular/issues/21708)) ([dd86790](https://github.com/angular/angular/commit/dd86790)) +* **compiler-cli:** do not lower expressions in non-modules ([#21649](https://github.com/angular/angular/issues/21649)) ([7f93aad](https://github.com/angular/angular/commit/7f93aad)) +* **router:** don't use ParamsInheritanceStrategy in declarations ([#21574](https://github.com/angular/angular/issues/21574)) ([925e654](https://github.com/angular/angular/commit/925e654)), closes [#21456](https://github.com/angular/angular/issues/21456) + + +### Features + +* **compiler:** implement "enableIvy" compiler option ([#21427](https://github.com/angular/angular/issues/21427)) ([64d16de](https://github.com/angular/angular/commit/64d16de)) +* **core:** optional generic type for ElementRef ([#20765](https://github.com/angular/angular/issues/20765)) ([d3d9aac](https://github.com/angular/angular/commit/d3d9aac)), closes [#13139](https://github.com/angular/angular/issues/13139) + + + + +## [5.2.2](https://github.com/angular/angular/compare/5.2.1...5.2.2) (2018-01-25) + + +### Bug Fixes + +* **common:** A null value should remove the style on IE ([#21679](https://github.com/angular/angular/issues/21679)) ([c12ea3a](https://github.com/angular/angular/commit/c12ea3a)), closes [#21064](https://github.com/angular/angular/issues/21064) +* **common:** don't remove special characters when extracting CLDR data ([#21626](https://github.com/angular/angular/issues/21626)) ([a62c186](https://github.com/angular/angular/commit/a62c186)) +* **common:** extract plural function from i18n locale data files for TS 2.6 ([#21626](https://github.com/angular/angular/issues/21626)) ([71f9eaa](https://github.com/angular/angular/commit/71f9eaa)), closes [#21608](https://github.com/angular/angular/issues/21608) +* **common:** fallback to last defined value for named date and time formats ([#21299](https://github.com/angular/angular/issues/21299)) ([982eb7b](https://github.com/angular/angular/commit/982eb7b)), closes [#21282](https://github.com/angular/angular/issues/21282) +* **compiler:** add support for marker tags in xliff serializers ([#21250](https://github.com/angular/angular/issues/21250)) ([02352bc](https://github.com/angular/angular/commit/02352bc)), closes [#21078](https://github.com/angular/angular/issues/21078) +* **compiler:** Don't strip `/*# sourceURL ... */` ([#16088](https://github.com/angular/angular/issues/16088)) ([de6c644](https://github.com/angular/angular/commit/de6c644)) +* **compiler:** fix ICU select messages to use male/female/other ([#21713](https://github.com/angular/angular/issues/21713)) ([8e44577](https://github.com/angular/angular/commit/8e44577)) +* **compiler-cli:** do not fold errors past calls in the collector ([#21708](https://github.com/angular/angular/issues/21708)) ([52970c0](https://github.com/angular/angular/commit/52970c0)) +* **compiler-cli:** do not lower expressions in non-modules ([#21649](https://github.com/angular/angular/issues/21649)) ([ba4ea82](https://github.com/angular/angular/commit/ba4ea82)) +* **router:** don't use ParamsInheritanceStrategy in declarations ([#21574](https://github.com/angular/angular/issues/21574)) ([8b3fbb5](https://github.com/angular/angular/commit/8b3fbb5)), closes [#21456](https://github.com/angular/angular/issues/21456) + + + + +# [6.0.0-beta.0](https://github.com/angular/angular/compare/5.2.0...6.0.0-beta.0) (2018-01-17) + + +### Bug Fixes + +* **animations:** fix increment/decrement aliases example ([#18323](https://github.com/angular/angular/issues/18323)) ([d2aa8ac](https://github.com/angular/angular/commit/d2aa8ac)) +* **benchpress:** should still support selenium_webdriver < 3.6.0 ([#21477](https://github.com/angular/angular/issues/21477)) ([9b84a32](https://github.com/angular/angular/commit/9b84a32)) +* **common:** set correct timezone for ISO8601 dates in Safari ([#21506](https://github.com/angular/angular/issues/21506)) ([05208b8](https://github.com/angular/angular/commit/05208b8)), closes [#21491](https://github.com/angular/angular/issues/21491) +* **compiler:** cache external reference resolution ([#21359](https://github.com/angular/angular/issues/21359)) ([e3e2fc0](https://github.com/angular/angular/commit/e3e2fc0)) +* **compiler:** make `.ngsummary.json` files idempotent ([#21448](https://github.com/angular/angular/issues/21448)) ([e64b1e9](https://github.com/angular/angular/commit/e64b1e9)) +* **core:** fix chained http call ([#20924](https://github.com/angular/angular/issues/20924)) ([7e3f9a4](https://github.com/angular/angular/commit/7e3f9a4)), closes [#20921](https://github.com/angular/angular/issues/20921) +* **ivy:** Add workaround for AJD in google3 ([#21488](https://github.com/angular/angular/issues/21488)) ([6af3672](https://github.com/angular/angular/commit/6af3672)) +* **language-service:** Clear caches when program changes ([#21337](https://github.com/angular/angular/issues/21337)) ([43e1520](https://github.com/angular/angular/commit/43e1520)), closes [#19405](https://github.com/angular/angular/issues/19405) +* **service-worker:** properly handle invalid hashes in all scenarios ([#21288](https://github.com/angular/angular/issues/21288)) ([3951098](https://github.com/angular/angular/commit/3951098)) + + +### Features + +* **bazel:** allow ng_module rules to control whether type checking is enabled ([#21460](https://github.com/angular/angular/issues/21460)) ([cffa0fe](https://github.com/angular/angular/commit/cffa0fe)) +* **core:** add binding name to content changed error ([#20352](https://github.com/angular/angular/issues/20352)) ([d3bf54b](https://github.com/angular/angular/commit/d3bf54b)) +* **forms:** handle string with and without line boundary on pattern validator ([#19256](https://github.com/angular/angular/issues/19256)) ([54bf179](https://github.com/angular/angular/commit/54bf179)) + + +### Performance Improvements + +* **ivy:** add missing dom element in render3_function tree benchmark ([#21476](https://github.com/angular/angular/issues/21476)) ([9b5a485](https://github.com/angular/angular/commit/9b5a485)) + + + + +## [5.2.1](https://github.com/angular/angular/compare/5.2.0...5.2.1) (2018-01-17) + + +### Bug Fixes + +* **animations:** fix increment/decrement aliases example ([#18323](https://github.com/angular/angular/issues/18323)) ([48c1898](https://github.com/angular/angular/commit/48c1898)) +* **benchpress:** should still support selenium_webdriver < 3.6.0 ([#21477](https://github.com/angular/angular/issues/21477)) ([3c6a506](https://github.com/angular/angular/commit/3c6a506)) +* **common:** set correct timezone for ISO8601 dates in Safari ([#21506](https://github.com/angular/angular/issues/21506)) ([8e9cd57](https://github.com/angular/angular/commit/8e9cd57)), closes [#21491](https://github.com/angular/angular/issues/21491) +* **compiler:** cache external reference resolution ([#21359](https://github.com/angular/angular/issues/21359)) ([c32e833](https://github.com/angular/angular/commit/c32e833)) +* **compiler:** make `.ngsummary.json` files idempotent ([#21448](https://github.com/angular/angular/issues/21448)) ([a931a41](https://github.com/angular/angular/commit/a931a41)) +* **core:** fix chained http call ([#20924](https://github.com/angular/angular/issues/20924)) ([54e7576](https://github.com/angular/angular/commit/54e7576)), closes [#20921](https://github.com/angular/angular/issues/20921) +* **language-service:** Clear caches when program changes ([#21337](https://github.com/angular/angular/issues/21337)) ([cc9419d](https://github.com/angular/angular/commit/cc9419d)), closes [#19405](https://github.com/angular/angular/issues/19405) +* **service-worker:** properly handle invalid hashes in all scenarios ([#21288](https://github.com/angular/angular/issues/21288)) ([51eb3d4](https://github.com/angular/angular/commit/51eb3d4)) + + +### Features + +* **core:** add binding name to content changed error ([#20352](https://github.com/angular/angular/issues/20352)) ([4556532](https://github.com/angular/angular/commit/4556532)) +* **forms:** handle string with and without line boundary on pattern validator ([#19256](https://github.com/angular/angular/issues/19256)) ([75f8522](https://github.com/angular/angular/commit/75f8522)) + + + + +# [5.2.0](https://github.com/angular/angular/compare/5.2.0-rc.0...5.2.0) (2018-01-10) + + +### Bug Fixes + +* **bazel:** Give correct module names for ES6 output ([#21320](https://github.com/angular/angular/issues/21320)) ([9728dce](https://github.com/angular/angular/commit/9728dce)), closes [#21022](https://github.com/angular/angular/issues/21022) +* **benchpress:** forward compat with selenium_webdriver 3.6.0 ([#21399](https://github.com/angular/angular/issues/21399)) ([6040ee3](https://github.com/angular/angular/commit/6040ee3)) +* **benchpress:** work around missing events from Chrome 63 ([#21396](https://github.com/angular/angular/issues/21396)) ([fa03ae1](https://github.com/angular/angular/commit/fa03ae1)) +* **common:** export currencies via `getCurrencySymbol` ([#20983](https://github.com/angular/angular/issues/20983)) ([fecf768](https://github.com/angular/angular/commit/fecf768)) + +Note: Due to an animation fix back in 5.1.1 ([c2b3792](https://github.com/angular/angular/commit/c2b3792a3b5fa5215fe2ef7e0ac6511086ffe4c1)) which allows for nested :leave queries to work within animation sequences, all elements that are dynamically inserted (*ngIf, *ngFor, etc…) now contain the special CSS class: “ng-star-inserted”. This may cause failures within unit tests if there are any assertions that match against element.className directly. (An easy fix for this is to match using a regular expression instead of asserting the className string directly.) + # [5.2.0-rc.0](https://github.com/angular/angular/compare/5.2.0-beta.1...5.2.0-rc.0) (2018-01-04) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7a97199884..74cec311bc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,7 +51,7 @@ and help you to craft the change so that it is successfully accepted into the pr Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available. -We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a minimal reproduction scenario using http://plnkr.co. Having a live, reproducible scenario gives us wealth of important information without going back & forth to you with additional questions like: +We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs, we will systematically ask you to provide a minimal reproduction scenario using http://plnkr.co. Having a live, reproducible scenario gives us a wealth of important information without going back & forth to you with additional questions like: - version of Angular used - 3rd-party libraries and their versions @@ -61,7 +61,7 @@ A minimal reproduce scenario using http://plnkr.co/ allows us to quickly confirm We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it. -Unfortunately we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced. +Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that doesn't have enough info to be reproduced. You can file new issues by filling out our [new issue form](https://github.com/angular/angular/issues/new). @@ -72,7 +72,7 @@ Before you submit your Pull Request (PR) consider the following guidelines: 1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR that relates to your submission. You don't want to duplicate effort. 1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs. - We cannot accept code without this. + We cannot accept code without this. Make sure you sign with the primary email address of the Git identity that has been granted access to the Angular repository. 1. Fork the angular/angular repo. 1. Make your changes in a new git branch: @@ -173,12 +173,12 @@ The **header** is mandatory and the **scope** of the header is optional. Any line of the commit message cannot be longer 100 characters! This allows the message to be easier to read on GitHub as well as in various git tools. -Footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any. +The footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any. Samples: (even more [samples](https://github.com/angular/angular/commits/master)) ``` -docs(changelog): update change log to beta.5 +docs(changelog): update changelog to beta.5 ``` ``` fix(release): need to depend on latest rxjs and zone.js @@ -203,7 +203,7 @@ Must be one of the following: * **test**: Adding missing tests or correcting existing tests ### Scope -The scope should be the name of the npm package affected (as perceived by person reading changelog generated from commit messages. +The scope should be the name of the npm package affected (as perceived by the person reading the changelog generated from commit messages. The following is the list of supported scopes: @@ -232,10 +232,10 @@ There are currently a few exceptions to the "use package name" rule: * 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 succinct description of the change: +The subject contains a succinct description of the change: * use the imperative, present tense: "change" not "changed" nor "changes" -* don't capitalize first letter +* don't capitalize the first letter * no dot (.) at the end ### Body @@ -259,6 +259,19 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise * For corporations we'll need you to [print, sign and one of scan+email, fax or mail the form][corporate-cla]. +
+ customer-dashboard works! +
+ diff --git a/aio/content/examples/feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.spec.ts b/aio/content/examples/feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.spec.ts new file mode 100644 index 0000000000..2420d05521 --- /dev/null +++ b/aio/content/examples/feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CustomerDashboardComponent } from './customer-dashboard.component'; + +describe('CustomerDashboardComponent', () => { + let component: CustomerDashboardComponent; + let fixture: ComponentFixtureHeroes API URL is "{{config.heroesUrl}}"
+Textfile URL is "{{config.textfile}}"
+{{error | json}}
diff --git a/aio/content/examples/http/src/app/config/config.component.ts b/aio/content/examples/http/src/app/config/config.component.ts new file mode 100644 index 0000000000..f372c81b79 --- /dev/null +++ b/aio/content/examples/http/src/app/config/config.component.ts @@ -0,0 +1,78 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; +import { Config, ConfigService } from './config.service'; +import { MessageService } from '../message.service'; + +@Component({ + selector: 'app-config', + templateUrl: './config.component.html', + providers: [ ConfigService ], + styles: ['.error {color: red;}'] +}) +export class ConfigComponent { + error: any; + headers: string[]; + // #docregion v2 + config: Config; + + // #enddocregion v2 + constructor(private configService: ConfigService) {} + + clear() { + this.config = undefined; + this.error = undefined; + this.headers = undefined; + } + + // #docregion v1, v2, v3 + showConfig() { + this.configService.getConfig() + // #enddocregion v1, v2 + .subscribe( + data => this.config = { ...data }, // success path + error => this.error = error // error path + ); + } + // #enddocregion v3 + + showConfig_v1() { + this.configService.getConfig_1() + // #docregion v1, v1_callback + .subscribe(data => this.config = { + heroesUrl: data['heroesUrl'], + textfile: data['textfile'] + }); + // #enddocregion v1_callback + } + // #enddocregion v1 + + showConfig_v2() { + this.configService.getConfig() + // #docregion v2, v2_callback + // clone the data object, using its known Config shape + .subscribe(data => this.config = { ...data }); + // #enddocregion v2_callback + } + // #enddocregion v2 + +// #docregion showConfigResponse + showConfigResponse() { + this.configService.getConfigResponse() + // resp is of type `HttpResponseContents: "{{contents}}"
diff --git a/aio/content/examples/http/src/app/downloader/downloader.component.ts b/aio/content/examples/http/src/app/downloader/downloader.component.ts new file mode 100644 index 0000000000..21216d1c63 --- /dev/null +++ b/aio/content/examples/http/src/app/downloader/downloader.component.ts @@ -0,0 +1,23 @@ +import { Component } from '@angular/core'; +import { DownloaderService } from './downloader.service'; + +@Component({ + selector: 'app-downloader', + templateUrl: './downloader.component.html', + providers: [ DownloaderService ] +}) +export class DownloaderComponent { + contents: string; + constructor(private downloaderService: DownloaderService) {} + + clear() { + this.contents = undefined; + } + + // #docregion download + download() { + this.downloaderService.getTextFile('assets/textfile.txt') + .subscribe(results => this.contents = results); + } + // #enddocregion download +} diff --git a/aio/content/examples/http/src/app/downloader/downloader.service.ts b/aio/content/examples/http/src/app/downloader/downloader.service.ts new file mode 100644 index 0000000000..e10a4f2b35 --- /dev/null +++ b/aio/content/examples/http/src/app/downloader/downloader.service.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +import { tap } from 'rxjs/operators'; + +import { MessageService } from '../message.service'; + +@Injectable() +export class DownloaderService { + constructor( + private http: HttpClient, + private messageService: MessageService) { } + + // #docregion getTextFile + getTextFile(filename: string) { + // The Observable returned by get() is of type ObservableSearches when typing stops. Caches for 30 seconds.
+ + + + + + + +{{errorMessage}}
diff --git a/aio/content/examples/http/src/app/toh/hero-list.component.promise.ts b/aio/content/examples/http/src/app/toh/hero-list.component.promise.ts deleted file mode 100644 index 4bbe7eade2..0000000000 --- a/aio/content/examples/http/src/app/toh/hero-list.component.promise.ts +++ /dev/null @@ -1,40 +0,0 @@ -// #docregion -// Promise Version -import { Component, OnInit } from '@angular/core'; -import { Hero } from './hero'; -import { HeroService } from './hero.service.promise'; - -@Component({ - selector: 'hero-list-promise', - templateUrl: './hero-list.component.html', - providers: [ HeroService ], - styles: ['.error {color:red;}'] -}) -// #docregion component -export class HeroListPromiseComponent implements OnInit { - errorMessage: string; - heroes: Hero[]; - mode = 'Promise'; - - constructor (private heroService: HeroService) {} - - ngOnInit() { this.getHeroes(); } - - // #docregion methods - getHeroes() { - this.heroService.getHeroes() - .then( - heroes => this.heroes = heroes, - error => this.errorMessage =Search when typing stops
- -Search after each keystroke
- -+ customer-list works! +
diff --git a/aio/content/examples/lazy-loading-ngmodules/src/app/customers/customer-list/customer-list.component.spec.ts b/aio/content/examples/lazy-loading-ngmodules/src/app/customers/customer-list/customer-list.component.spec.ts new file mode 100644 index 0000000000..c34e342ba0 --- /dev/null +++ b/aio/content/examples/lazy-loading-ngmodules/src/app/customers/customer-list/customer-list.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CustomerListComponent } from './customer-list.component'; + +describe('CustomerListComponent', () => { + let component: CustomerListComponent; + let fixture: ComponentFixture+ order-list works! +
diff --git a/aio/content/examples/lazy-loading-ngmodules/src/app/orders/order-list/order-list.component.spec.ts b/aio/content/examples/lazy-loading-ngmodules/src/app/orders/order-list/order-list.component.spec.ts new file mode 100644 index 0000000000..2688bcf420 --- /dev/null +++ b/aio/content/examples/lazy-loading-ngmodules/src/app/orders/order-list/order-list.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OrderListComponent } from './order-list.component'; + +describe('OrderListComponent', () => { + let component: OrderListComponent; + let fixture: ComponentFixture+ Welcome, {{user}} +
diff --git a/aio/content/examples/ngmodules/src/app/core/title.component.ts b/aio/content/examples/ngmodules/src/app/core/title.component.ts new file mode 100644 index 0000000000..979a5803ab --- /dev/null +++ b/aio/content/examples/ngmodules/src/app/core/title.component.ts @@ -0,0 +1,15 @@ +import { Component, Input } from '@angular/core'; +import { UserService } from '../core/user.service'; + +@Component({ + selector: 'app-title', + templateUrl: './title.component.html', +}) +export class TitleComponent { + title = 'NgModules'; + user = ''; + + constructor(userService: UserService) { + this.user = userService.userName; + } +} diff --git a/aio/content/examples/ngmodules/src/app/core/user.service.ts b/aio/content/examples/ngmodules/src/app/core/user.service.ts new file mode 100644 index 0000000000..d1ab1cd6b3 --- /dev/null +++ b/aio/content/examples/ngmodules/src/app/core/user.service.ts @@ -0,0 +1,31 @@ +// Proves that UserService is an app-wide singleton and only instantiated once +// IFF shared.module follows the `forRoot` pattern. +// +// If it didn't, a new instance of UserService would be created +// after each lazy load and the userName would double up. + +import { Injectable, Optional } from '@angular/core'; + +let nextId = 1; + +export class UserServiceConfig { + userName = 'Philip Marlowe'; +} + +@Injectable() +export class UserService { + id = nextId++; + private _userName = 'Sherlock Holmes'; + + // #docregion ctor + constructor(@Optional() config: UserServiceConfig) { + if (config) { this._userName = config.userName; } + } + // #enddocregion ctor + + get userName() { + // Demo: add a suffix if this service has been created more than once + const suffix = this.id > 1 ? ` times ${this.id}` : ''; + return this._userName + suffix; + } +} diff --git a/aio/content/examples/ngmodules/src/app/customers/customers-detail.component.ts b/aio/content/examples/ngmodules/src/app/customers/customers-detail.component.ts new file mode 100644 index 0000000000..11683c9d68 --- /dev/null +++ b/aio/content/examples/ngmodules/src/app/customers/customers-detail.component.ts @@ -0,0 +1,31 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { Customer, + CustomersService } from './customers.service'; + +@Component({ + template: ` +
+ items works! +
diff --git a/aio/content/examples/ngmodules/src/app/items/items.component.spec.ts b/aio/content/examples/ngmodules/src/app/items/items.component.spec.ts new file mode 100644 index 0000000000..b77cce74ec --- /dev/null +++ b/aio/content/examples/ngmodules/src/app/items/items.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ItemsComponent } from './items.component'; + +describe('ItemsComponent', () => { + let component: ItemsComponent; + let fixture: ComponentFixtureobservable|async
:
+ Time: {{ time | async }}All about this sample
` + ` }) export class AboutComponent { } diff --git a/aio/content/examples/testing/src/app/app-initial.component.spec.ts b/aio/content/examples/testing/src/app/app-initial.component.spec.ts new file mode 100644 index 0000000000..3e3e6a847c --- /dev/null +++ b/aio/content/examples/testing/src/app/app-initial.component.spec.ts @@ -0,0 +1,76 @@ +// #docplaster +// #docregion +import { TestBed, async } from '@angular/core/testing'; +// #enddocregion +import { AppComponent } from './app-initial.component'; +/* +// #docregion +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { +// #enddocregion +*/ +describe('AppComponent (initial CLI version)', () => { + // #docregion + 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.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); + })); +}); +// #enddocregion + +/// As it should be +import { DebugElement } from '@angular/core'; +import { ComponentFixture } from '@angular/core/testing'; + +describe('AppComponent (initial CLI version - as it should be)', () => { + + let app: AppComponent; + let de: DebugElement; + let fixture: ComponentFixturewith "banner works!"', () => { + // #docregion nativeElement + const bannerElement: HTMLElement = fixture.nativeElement; + // #enddocregion nativeElement + const p = bannerElement.querySelector('p'); + expect(p.textContent).toEqual('banner works!'); + }); +// #enddocregion v4-test-3 + + +// #docregion v4-test-4 +it('should find the
with fixture.debugElement.nativeElement)', () => { + // #docregion debugElement-nativeElement + const bannerDe: DebugElement = fixture.debugElement; + const bannerEl: HTMLElement = bannerDe.nativeElement; + // #enddocregion debugElement-nativeElement + const p = bannerEl.querySelector('p'); + expect(p.textContent).toEqual('banner works!'); +}); +// #enddocregion v4-test-4 + +// #docregion v4-test-5 +it('should find the
with fixture.debugElement.query(By.css)', () => { + const bannerDe: DebugElement = fixture.debugElement; + const paragraphDe = bannerDe.query(By.css('p')); + const p: HTMLElement = paragraphDe.nativeElement; + expect(p.textContent).toEqual('banner works!'); +}); +// #enddocregion v4-test-5 +// #docregion v3 +}); +// #enddocregion v3, v4 diff --git a/aio/content/examples/testing/src/app/banner/banner-initial.component.ts b/aio/content/examples/testing/src/app/banner/banner-initial.component.ts new file mode 100644 index 0000000000..a7959e5573 --- /dev/null +++ b/aio/content/examples/testing/src/app/banner/banner-initial.component.ts @@ -0,0 +1,10 @@ +// BannerComponent as initially generated by the CLI +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-banner', + template: `
banner works!
`, + styles: [] +}) +export class BannerComponent { } diff --git a/aio/content/examples/testing/src/app/banner.component.detect-changes.spec.ts b/aio/content/examples/testing/src/app/banner/banner.component.detect-changes.spec.ts similarity index 76% rename from aio/content/examples/testing/src/app/banner.component.detect-changes.spec.ts rename to aio/content/examples/testing/src/app/banner/banner.component.detect-changes.spec.ts index 412f5be586..3310fbdad0 100644 --- a/aio/content/examples/testing/src/app/banner.component.detect-changes.spec.ts +++ b/aio/content/examples/testing/src/app/banner/banner.component.detect-changes.spec.ts @@ -7,53 +7,45 @@ import { async } from '@angular/core/testing'; import { ComponentFixtureAutoDetect } from '@angular/core/testing'; // #enddocregion import-ComponentFixtureAutoDetect import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { DebugElement } from '@angular/core'; import { BannerComponent } from './banner.component'; describe('BannerComponent (AutoChangeDetect)', () => { let comp: BannerComponent; let fixture: ComponentFixture{{quote}}
' -}) -export class TwainComponent implements OnInit, OnDestroy { - intervalId: number; - quote = '-- not initialized yet --'; - constructor(private twainService: TwainService) { } - - getQuote() { - this.twainService.getQuote().then(quote => this.quote = quote); - } - - ngOnInit(): void { - this.getQuote(); - this.intervalId = window.setInterval(() => this.getQuote(), 5000); - } - - ngOnDestroy(): void { - clearInterval(this.intervalId); - } -} diff --git a/aio/content/examples/testing/src/app/shared/twain.component.ts b/aio/content/examples/testing/src/app/shared/twain.component.ts deleted file mode 100644 index 29f24459ab..0000000000 --- a/aio/content/examples/testing/src/app/shared/twain.component.ts +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion -import { Component, OnInit } from '@angular/core'; - -import { TwainService } from './twain.service'; - -// #docregion component -@Component({ - selector: 'twain-quote', - template: '{{quote}}
' -}) -export class TwainComponent implements OnInit { - intervalId: number; - quote = '...'; - constructor(private twainService: TwainService) { } - - ngOnInit(): void { - this.twainService.getQuote().then(quote => this.quote = quote); - } -} -// #enddocregion component diff --git a/aio/content/examples/testing/src/app/shared/twain.service.ts b/aio/content/examples/testing/src/app/shared/twain.service.ts deleted file mode 100644 index 9e394df1ee..0000000000 --- a/aio/content/examples/testing/src/app/shared/twain.service.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Injectable } from '@angular/core'; - -const quotes = [ -'Always do right. This will gratify some people and astonish the rest.', -'I have never let my schooling interfere with my education.', -'Don\'t go around saying the world owes you a living. The world owes you nothing. It was here first.', -'Whenever you find yourself on the side of the majority, it is time to pause and reflect.', -'If you tell the truth, you don\'t have to remember anything.', -'Clothes make the man. Naked people have little or no influence on society.', -'It\'s not the size of the dog in the fight, it\'s the size of the fight in the dog.', -'Truth is stranger than fiction, but it is because Fiction is obliged to stick to possibilities; Truth isn\'t.', -'The man who does not read good books has no advantage over the man who cannot read them.', -'Get your facts first, and then you can distort them as much as you please.', -]; - -@Injectable() -export class TwainService { - private next = 0; - - // Imaginary todo: get quotes from a remote quote service - // returns quote after delay simulating server latency - getQuote(): Promise{{quote | async}}
+ +{{ errorMessage }}
`, + // #enddocregion template + styles: [ + `.twain { font-style: italic; } .error { color: red; }` + ] + +}) +export class TwainComponent implements OnInit { + errorMessage: string; + quote: Observable(`api/quotes/${id}`)), + // tap((q : Quote) => console.log(q)), + map((q: Quote) => q.quote), + + // `errors` is observable of http.get errors + retryWhen(errors => errors.pipe( + switchMap((error: HttpErrorResponse) => { + if (error.status === 404) { + // Queried for quote that doesn't exist. + this.nextId = 1; // retry with quote id:1 + return of(null); // signal OK to retry + } + // Some other HTTP error. + console.error(error); + return new ErrorObservable('Cannot get Twain quotes from the server'); + }), + take(2), + // If a second retry value, then didn't find id:1 and triggers the following error + concat(new ErrorObservable('There are no Twain quotes')) // didn't find id:1 + )) + ); + } +} + diff --git a/aio/content/examples/testing/src/app/welcome.component.spec.ts b/aio/content/examples/testing/src/app/welcome/welcome.component.spec.ts similarity index 67% rename from aio/content/examples/testing/src/app/welcome.component.spec.ts rename to aio/content/examples/testing/src/app/welcome/welcome.component.spec.ts index e506dda396..25f3b28c77 100644 --- a/aio/content/examples/testing/src/app/welcome.component.spec.ts +++ b/aio/content/examples/testing/src/app/welcome/welcome.component.spec.ts @@ -1,26 +1,66 @@ // #docplaster import { ComponentFixture, inject, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { DebugElement } from '@angular/core'; -import { UserService } from './model'; +import { UserService } from '../model/user.service'; import { WelcomeComponent } from './welcome.component'; +// #docregion mock-user-service +class MockUserService { + isLoggedIn = true; + user = { name: 'Test User'}; +}; +// #enddocregion mock-user-service + +describe('WelcomeComponent (class only)', () => { + let comp: WelcomeComponent; + let userService: UserService; + + // #docregion class-only-before-each + beforeEach(() => { + TestBed.configureTestingModule({ + // provide the component-under-test and dependent service + providers: [ + WelcomeComponent, + { provide: UserService, useClass: MockUserService } + ] + }); + // inject both the component and the dependent service. + comp = TestBed.get(WelcomeComponent); + userService = TestBed.get(UserService); + }); + // #enddocregion class-only-before-each + + // #docregion class-only-tests + it('should not have welcome message after construction', () => { + expect(comp.welcome).toBeUndefined(); + }); + + it('should welcome logged in user after Angular calls ngOnInit', () => { + comp.ngOnInit(); + expect(comp.welcome).toContain(userService.user.name); + }); + + it('should ask user to log in if not logged in after ngOnInit', () => { + userService.isLoggedIn = false; + comp.ngOnInit(); + expect(comp.welcome).not.toContain(userService.user.name); + expect(comp.welcome).toContain('log in'); + }); + // #enddocregion class-only-tests +}); + describe('WelcomeComponent', () => { let comp: WelcomeComponent; let fixture: ComponentFixture; let componentUserService: UserService; // the actually injected service let userService: UserService; // the TestBed injected service - let de: DebugElement; // the DebugElement with the welcome message let el: HTMLElement; // the DOM element with the welcome message - let userServiceStub: { - isLoggedIn: boolean; - user: { name: string} - }; + // #docregion setup, user-service-stub + let userServiceStub: Partial ; - // #docregion setup + // #enddocregion user-service-stub beforeEach(() => { // stub UserService for test purposes // #docregion user-service-stub @@ -57,8 +97,7 @@ describe('WelcomeComponent', () => { // #enddocregion inject-from-testbed // get the "welcome" element by CSS selector (e.g., by class name) - de = fixture.debugElement.query(By.css('.welcome')); - el = de.nativeElement; + el = fixture.nativeElement.querySelector('.welcome'); }); // #enddocregion setup @@ -85,12 +124,10 @@ describe('WelcomeComponent', () => { }); // #enddocregion tests - // #docregion inject-it it('should inject the component\'s UserService instance', inject([UserService], (service: UserService) => { expect(service).toBe(componentUserService); })); - // #enddocregion inject-it it('TestBed and Component UserService should be the same', () => { expect(userService === componentUserService).toBe(true); diff --git a/aio/content/examples/testing/src/app/welcome.component.ts b/aio/content/examples/testing/src/app/welcome/welcome.component.ts similarity index 50% rename from aio/content/examples/testing/src/app/welcome.component.ts rename to aio/content/examples/testing/src/app/welcome/welcome.component.ts index 9bc5ca33c4..802f30cc4a 100644 --- a/aio/content/examples/testing/src/app/welcome.component.ts +++ b/aio/content/examples/testing/src/app/welcome/welcome.component.ts @@ -1,19 +1,20 @@ // #docregion import { Component, OnInit } from '@angular/core'; +import { UserService } from '../model/user.service'; -import { UserService } from './model/user.service'; - +// #docregion component @Component({ selector: 'app-welcome', - template: ' {{welcome}}
' + template: '{{welcome}}
' }) +// #docregion class export class WelcomeComponent implements OnInit { - welcome = '-- not initialized yet --'; + welcome: string; constructor(private userService: UserService) { } ngOnInit(): void { this.welcome = this.userService.isLoggedIn ? - 'Welcome, ' + this.userService.user.name : - 'Please log in.'; + 'Welcome, ' + this.userService.user.name : 'Please log in.'; } } +// #enddocregion component, class diff --git a/aio/content/examples/testing/src/bag-specs.html b/aio/content/examples/testing/src/bag-specs.html deleted file mode 100644 index 89b46f7056..0000000000 --- a/aio/content/examples/testing/src/bag-specs.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - -- Specs Bag - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/aio/content/examples/testing/src/bag.html b/aio/content/examples/testing/src/bag.html deleted file mode 100644 index 3e0fcb9025..0000000000 --- a/aio/content/examples/testing/src/bag.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - -- Specs Bag - - - - - - - - - - - - - - - -Loading ... - - diff --git a/aio/content/examples/testing/src/banner-inline-specs.html b/aio/content/examples/testing/src/banner-inline-specs.html deleted file mode 100644 index 2a512a5647..0000000000 --- a/aio/content/examples/testing/src/banner-inline-specs.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - -- Banner Component (inline template) Specs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/aio/content/examples/testing/src/banner-specs.html b/aio/content/examples/testing/src/banner-specs.html deleted file mode 100644 index d16dd977a4..0000000000 --- a/aio/content/examples/testing/src/banner-specs.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - -- Banner Component Specs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/aio/content/examples/testing/src/browser-test-shim.js b/aio/content/examples/testing/src/browser-test-shim.js deleted file mode 100644 index ee21831e22..0000000000 --- a/aio/content/examples/testing/src/browser-test-shim.js +++ /dev/null @@ -1,87 +0,0 @@ -// BROWSER TESTING SHIM -// Keep it in-sync with what karma-test-shim does -// #docregion -/*global jasmine, __karma__, window*/ -(function () { - -Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing. - -// Uncomment to get full stacktrace output. Sometimes helpful, usually not. -// Error.stackTraceLimit = Infinity; // - -jasmine.DEFAULT_TIMEOUT_INTERVAL = 3000; - -var baseURL = document.baseURI; -baseURL = baseURL + baseURL[baseURL.length-1] ? '' : '/'; - -System.config({ - baseURL: baseURL, - // Extend usual application package list with test folder - packages: { 'testing': { main: 'index.js', defaultExtension: 'js' } }, - - // Assume npm: is set in `paths` in systemjs.config - // Map the angular testing umd bundles - map: { - '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js', - '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js', - '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js', - '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js', - '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js', - '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js', - '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js', - '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js', - }, -}); - -System.import('systemjs.config.js') - .then(importSystemJsExtras) - .then(initTestBed) - .then(initTesting); - -/** Optional SystemJS configuration extras. Keep going w/o it */ -function importSystemJsExtras(){ - return System.import('systemjs.config.extras.js') - .catch(function(reason) { - console.log( - 'Note: System.import could not load "systemjs.config.extras.js" where you might have added more configuration. It is an optional file so we will continue without it.' - ); - console.log(reason); - }); -} - -function initTestBed(){ - return Promise.all([ - System.import('@angular/core/testing'), - System.import('@angular/platform-browser-dynamic/testing') - ]) - - .then(function (providers) { - var coreTesting = providers[0]; - var browserTesting = providers[1]; - - coreTesting.TestBed.initTestEnvironment( - browserTesting.BrowserDynamicTestingModule, - browserTesting.platformBrowserDynamicTesting()); - }) -} - -// Import all spec files defined in the html (__spec_files__) -// and start Jasmine testrunner -function initTesting () { - console.log('loading spec files: '+__spec_files__.join(', ')); - return Promise.all( - __spec_files__.map(function(spec) { - return System.import(spec); - }) - ) - // After all imports load, re-execute `window.onload` which - // triggers the Jasmine test-runner start or explain what went wrong - .then(success, console.error.bind(console)); - - function success () { - console.log('Spec files loaded; starting Jasmine testrunner'); - window.onload(); - } -} - -})(); diff --git a/aio/content/examples/testing/src/expected.ts b/aio/content/examples/testing/src/expected.ts new file mode 100644 index 0000000000..5339fa9725 --- /dev/null +++ b/aio/content/examples/testing/src/expected.ts @@ -0,0 +1 @@ +/* Ignore. Satisfies static analysis of router config in app.component.router.spec.ts */ diff --git a/aio/content/examples/testing/src/index-specs.html b/aio/content/examples/testing/src/index-specs.html new file mode 100644 index 0000000000..ca132f6cd0 --- /dev/null +++ b/aio/content/examples/testing/src/index-specs.html @@ -0,0 +1,4 @@ + diff --git a/aio/content/examples/testing/src/main-specs.ts b/aio/content/examples/testing/src/main-specs.ts new file mode 100644 index 0000000000..4bb1949ae9 --- /dev/null +++ b/aio/content/examples/testing/src/main-specs.ts @@ -0,0 +1,45 @@ +import './testing/global-jasmine'; +import 'jasmine-core/lib/jasmine-core/jasmine-html.js'; +import 'jasmine-core/lib/jasmine-core/boot.js'; + +declare var jasmine; + +import './polyfills'; + +import 'zone.js/dist/async-test'; +import 'zone.js/dist/fake-async-test'; +import 'zone.js/dist/long-stack-trace-zone'; +import 'zone.js/dist/proxy.js'; +import 'zone.js/dist/sync-test'; +import 'zone.js/dist/jasmine-patch'; + +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +// Spec files to include in the Stackblitz tests +import './tests.sb.ts'; + +// + +bootstrap(); + +// + +function bootstrap () { + if (window['jasmineRef']) { + location.reload(); + return; + } else { + window.onload(undefined); + window['jasmineRef'] = jasmine.getEnv(); + } + + // First, initialize the Angular testing environment. + getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() + ); +} diff --git a/aio/content/examples/testing/src/test.css b/aio/content/examples/testing/src/test.css new file mode 100644 index 0000000000..6010a5d9ba --- /dev/null +++ b/aio/content/examples/testing/src/test.css @@ -0,0 +1 @@ +@import "~jasmine-core/lib/jasmine-core/jasmine.css" diff --git a/aio/content/examples/testing/src/testing/activated-route-stub.ts b/aio/content/examples/testing/src/testing/activated-route-stub.ts new file mode 100644 index 0000000000..04fb7cb92b --- /dev/null +++ b/aio/content/examples/testing/src/testing/activated-route-stub.ts @@ -0,0 +1,29 @@ +// export for convenience. +export { ActivatedRoute } from '@angular/router'; + +// #docregion activated-route-stub +import { ReplaySubject } from 'rxjs/ReplaySubject'; +import { convertToParamMap, ParamMap, Params } from '@angular/router'; + +/** + * An ActivateRoute test double with a `paramMap` observable. + * Use the `setParamMap()` method to add the next `paramMap` value. + */ +export class ActivatedRouteStub { + // Use a ReplaySubject to share previous values with subscribers + // and pump new values into the `paramMap` observable + private subject = new ReplaySubject(); + + constructor(initialParams?: Params) { + this.setParamMap(initialParams); + } + + /** The mock paramMap observable */ + readonly paramMap = this.subject.asObservable(); + + /** Set the paramMap observables's next value */ + setParamMap(params?: Params) { + this.subject.next(convertToParamMap(params)); + }; +} +// #enddocregion activated-route-stub diff --git a/aio/content/examples/testing/src/testing/async-observable-helpers.ts b/aio/content/examples/testing/src/testing/async-observable-helpers.ts new file mode 100644 index 0000000000..3282bcbe37 --- /dev/null +++ b/aio/content/examples/testing/src/testing/async-observable-helpers.ts @@ -0,0 +1,30 @@ +/* +* Mock async observables that return asynchronously. +* The observable either emits once and completes or errors. +* +* Must call `tick()` when test with `fakeAsync()`. +* +* THE FOLLOWING DON'T WORK +* Using `of().delay()` triggers TestBed errors; +* see https://github.com/angular/angular/issues/10127 . +* +* Using `asap` scheduler - as in `of(value, asap)` - doesn't work either. +*/ +import { Observable } from 'rxjs/Observable'; +import { defer } from 'rxjs/observable/defer'; + +// #docregion async-data +/** Create async observable that emits-once and completes + * after a JS engine turn */ +export function asyncData (data: T) { + return defer(() => Promise.resolve(data)); +} +// #enddocregion async-data + +// #docregion async-error +/** Create async observable error that errors + * after a JS engine turn */ +export function asyncError (errorObject: any) { + return defer(() => Promise.reject(errorObject)); +} +// #enddocregion async-error diff --git a/aio/content/examples/testing/src/testing/global-jasmine.ts b/aio/content/examples/testing/src/testing/global-jasmine.ts new file mode 100644 index 0000000000..560ff97d66 --- /dev/null +++ b/aio/content/examples/testing/src/testing/global-jasmine.ts @@ -0,0 +1,3 @@ +import jasmineRequire from 'jasmine-core/lib/jasmine-core/jasmine.js'; + +window['jasmineRequire'] = jasmineRequire; diff --git a/aio/content/examples/testing/src/testing/index.ts b/aio/content/examples/testing/src/testing/index.ts index e3de5164ca..1fddaf8c4d 100644 --- a/aio/content/examples/testing/src/testing/index.ts +++ b/aio/content/examples/testing/src/testing/index.ts @@ -1,8 +1,10 @@ import { DebugElement } from '@angular/core'; import { tick, ComponentFixture } from '@angular/core/testing'; +export * from './async-observable-helpers'; +export * from './activated-route-stub'; export * from './jasmine-matchers'; -export * from './router-stubs'; +export * from './router-link-directive-stub'; ///// Short utilities ///// diff --git a/aio/content/examples/testing/src/testing/router-link-directive-stub.ts b/aio/content/examples/testing/src/testing/router-link-directive-stub.ts new file mode 100644 index 0000000000..761529d726 --- /dev/null +++ b/aio/content/examples/testing/src/testing/router-link-directive-stub.ts @@ -0,0 +1,30 @@ +import { Directive, Input } from '@angular/core'; + +// export for convenience. +export { RouterLink} from '@angular/router'; + +/* tslint:disable:directive-class-suffix */ +// #docregion router-link +@Directive({ + selector: '[routerLink]', + host: { '(click)': 'onClick()' } +}) +export class RouterLinkDirectiveStub { + @Input('routerLink') linkParams: any; + navigatedTo: any = null; + + onClick() { + this.navigatedTo = this.linkParams; + } +} +// #enddocregion router-link + +/// Dummy module to satisfy Angular Language service. Never used. +import { NgModule } from '@angular/core'; + +@NgModule({ + declarations: [ + RouterLinkDirectiveStub + ] +}) +export class RouterStubsModule {} diff --git a/aio/content/examples/testing/src/testing/router-stubs.ts b/aio/content/examples/testing/src/testing/router-stubs.ts deleted file mode 100644 index 880302c7be..0000000000 --- a/aio/content/examples/testing/src/testing/router-stubs.ts +++ /dev/null @@ -1,58 +0,0 @@ - // export for convenience. -export { ActivatedRoute, Router, RouterLink, RouterOutlet} from '@angular/router'; - -import { Component, Directive, Injectable, Input } from '@angular/core'; -import { NavigationExtras } from '@angular/router'; - -// #docregion router-link -@Directive({ - selector: '[routerLink]', - host: { - '(click)': 'onClick()' - } -}) -export class RouterLinkStubDirective { - @Input('routerLink') linkParams: any; - navigatedTo: any = null; - - onClick() { - this.navigatedTo = this.linkParams; - } -} -// #enddocregion router-link - -@Component({selector: 'router-outlet', template: ''}) -export class RouterOutletStubComponent { } - -@Injectable() -export class RouterStub { - navigate(commands: any[], extras?: NavigationExtras) { } -} - - -// Only implements params and part of snapshot.paramMap -// #docregion activated-route-stub -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; -import { convertToParamMap, ParamMap } from '@angular/router'; - -@Injectable() -export class ActivatedRouteStub { - - // ActivatedRoute.paramMap is Observable - private subject = new BehaviorSubject(convertToParamMap(this.testParamMap)); - paramMap = this.subject.asObservable(); - - // Test parameters - private _testParamMap: ParamMap; - get testParamMap() { return this._testParamMap; } - set testParamMap(params: {}) { - this._testParamMap = convertToParamMap(params); - this.subject.next(this._testParamMap); - } - - // ActivatedRoute.snapshot.paramMap - get snapshot() { - return { paramMap: this.testParamMap }; - } -} -// #enddocregion activated-route-stub diff --git a/aio/content/examples/testing/src/app-specs.html b/aio/content/examples/testing/src/tests.html similarity index 75% rename from aio/content/examples/testing/src/app-specs.html rename to aio/content/examples/testing/src/tests.html index 7b7292ed7c..c988c457cb 100644 --- a/aio/content/examples/testing/src/app-specs.html +++ b/aio/content/examples/testing/src/tests.html @@ -31,23 +31,31 @@ diff --git a/aio/content/examples/testing/src/tests.sb.ts b/aio/content/examples/testing/src/tests.sb.ts new file mode 100644 index 0000000000..3f1c8fe61a --- /dev/null +++ b/aio/content/examples/testing/src/tests.sb.ts @@ -0,0 +1,26 @@ +// Import spec files individually for Stackblitz +import 'app/about/about.component.spec.ts'; +import 'app/app-initial.component.spec.ts'; +import 'app/app.component.router.spec.ts'; +import 'app/app.component.spec.ts'; +import 'app/banner/banner-initial.component.spec.ts'; +import 'app/banner/banner.component.spec.ts'; +import 'app/banner/banner.component.detect-changes.spec.ts'; +import 'app/banner/banner-external.component.spec.ts'; +import 'app/dashboard/dashboard-hero.component.spec.ts'; +import 'app/dashboard/dashboard.component.no-testbed.spec.ts'; +import 'app/dashboard/dashboard.component.spec.ts'; +import 'app/demo/async-helper.spec.ts'; +import 'app/demo/demo.spec.ts'; +import 'app/demo/demo.testbed.spec.ts'; +import 'app/hero/hero-detail.component.no-testbed.spec.ts'; +import 'app/hero/hero-detail.component.spec.ts'; +import 'app/hero/hero-list.component.spec.ts'; +import 'app/model/hero.service.spec.ts'; +import 'app/model/http-hero.service.spec.ts'; +import 'app/model/testing/http-client.spec.ts'; +import 'app/shared/highlight.directive.spec.ts'; +import 'app/shared/title-case.pipe.spec.ts'; +import 'app/twain/twain.component.spec.ts'; +import 'app/twain/twain.component.marbles.spec.ts'; +import 'app/welcome/welcome.component.spec.ts'; diff --git a/aio/content/examples/testing/stackblitz.json b/aio/content/examples/testing/stackblitz.json new file mode 100644 index 0000000000..d05e3dbb1a --- /dev/null +++ b/aio/content/examples/testing/stackblitz.json @@ -0,0 +1,19 @@ +{ + "description": "Heroes Test App", + "files":[ + "src/styles.css", + + "src/app/**/*.css", + "src/app/**/*.html", + "src/app/**/*.ts", + + "!src/app/bag/*.*", + + "!src/test.ts", + + "src/test.css", + "src/main.ts", + "src/index.html" + ], + "tags": ["testing"] +} diff --git a/aio/content/examples/toh-pt0/plnkr.json b/aio/content/examples/toh-pt0/stackblitz.json similarity index 87% rename from aio/content/examples/toh-pt0/plnkr.json rename to aio/content/examples/toh-pt0/stackblitz.json index 3caa575acd..c2cf48171f 100644 --- a/aio/content/examples/toh-pt0/plnkr.json +++ b/aio/content/examples/toh-pt0/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Tour of Heroes: Part 0", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/toh-pt1/plnkr.json b/aio/content/examples/toh-pt1/stackblitz.json similarity index 89% rename from aio/content/examples/toh-pt1/plnkr.json rename to aio/content/examples/toh-pt1/stackblitz.json index 5ac3b2d3ce..880b28fae6 100644 --- a/aio/content/examples/toh-pt1/plnkr.json +++ b/aio/content/examples/toh-pt1/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Tour of Heroes: Part 1", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/toh-pt2/plnkr.json b/aio/content/examples/toh-pt2/stackblitz.json similarity index 87% rename from aio/content/examples/toh-pt2/plnkr.json rename to aio/content/examples/toh-pt2/stackblitz.json index 08c7b9581a..8f3cefdaeb 100644 --- a/aio/content/examples/toh-pt2/plnkr.json +++ b/aio/content/examples/toh-pt2/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Tour of Heroes: Part 2", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/toh-pt3/plnkr.json b/aio/content/examples/toh-pt3/stackblitz.json similarity index 87% rename from aio/content/examples/toh-pt3/plnkr.json rename to aio/content/examples/toh-pt3/stackblitz.json index 829715877e..c4ef78dc9f 100644 --- a/aio/content/examples/toh-pt3/plnkr.json +++ b/aio/content/examples/toh-pt3/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Tour of Heroes: Part 3", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/toh-pt4/src/app/app.module.ts b/aio/content/examples/toh-pt4/src/app/app.module.ts index 70b26976da..f3cc34faff 100644 --- a/aio/content/examples/toh-pt4/src/app/app.module.ts +++ b/aio/content/examples/toh-pt4/src/app/app.module.ts @@ -21,7 +21,14 @@ import { MessagesComponent } from './messages/messages.component'; FormsModule ], // #docregion providers - providers: [ HeroService, MessageService ], + // #docregion providers-heroservice + providers: [ + HeroService, + // #enddocregion providers-heroservice + MessageService + // #docregion providers-heroservice + ], + // #enddocregion providers-heroservice // #enddocregion providers bootstrap: [ AppComponent ] }) diff --git a/aio/content/examples/toh-pt4/plnkr.json b/aio/content/examples/toh-pt4/stackblitz.json similarity index 87% rename from aio/content/examples/toh-pt4/plnkr.json rename to aio/content/examples/toh-pt4/stackblitz.json index 95987d95ce..1b3e442ac0 100644 --- a/aio/content/examples/toh-pt4/plnkr.json +++ b/aio/content/examples/toh-pt4/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Tour of Heroes: Part 4", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/toh-pt5/src/app/messages/messages.component.html b/aio/content/examples/toh-pt5/src/app/messages/messages.component.html index 1df7dfd989..8e86f5247d 100644 --- a/aio/content/examples/toh-pt5/src/app/messages/messages.component.html +++ b/aio/content/examples/toh-pt5/src/app/messages/messages.component.html @@ -3,6 +3,6 @@ Messages
-{{message}}+{{message}}
Class description goes here. This is a short and to the point one or two sentence description that easily introduces the reader to the class.
+
+ class Compiler {
+ compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T>
+ compileModuleAsync<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>>
+ compileModuleAndAllComponentsSync<T>(moduleType: Type<T>): ModuleWithComponentFactories<T>
+ compileModuleAndAllComponentsAsync<T>(moduleType: Type<T>): Promise<ModuleWithComponentFactories<T>>
+ clearCache(): void
+ clearCacheFor(type: Type<any>)
+ }
+
The longer class description goes here which can include multiple paragraphs.
+ Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham. +
+ constructor(element: any, keyframes: {
+ [key: string]: string | number;
+ }[], duration: number, delay: number, easing: string, previousPlayers: any[])
+
Property | +Type | +Description | +
---|---|---|
+ Property1
+ |
+ + | Description goes here | +
+ Property2
+ |
+ Type | +Description goes here | +
+ Property3
+ |
+ Type | +Description goes here | +
Method1Name( ) | +
---|
+ Description goes here ++ Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham. + |
+
Method2Name( ) | +||||
---|---|---|---|---|
+ Description goes here ++ Declaration+
+
+ Parameters+Returns+Returns information and results goes here. +Errors+Error information goes here ++ Further details provided as needed. Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. + Overloads+
+ Example: Descriptive Title of Method Example+Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham. + |
+
Intro description text about what the example is and how it can be used.
+
+ constructor(element: any, keyframes: {
+ [key: string]: string | number;
+ }[], duration: number, delay: number, easing: string, previousPlayers: any[])
+
Further explanation provided as needed. Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball.
+`, it also has some differences. Code like `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and ` `, it also has some differences. Code like `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and ` `这样的典型的 HTML 元素,还能使用其它元素。
例如,像`*ngFor`、`{{hero.name}}`、`(click)`、`[hero]`和`
+ latest
+
+ 最新版
+
- latest
-
- 最新版
-
- latest
-
- 最新版
- If AnimationBuilder is used then the polyfill will enable scrubbing
+ support for IE/Edge and Safari (Chrome and Firefox support this natively). 如果使用了AnimationBuilder,那么填充库将为 IE/Edge 和 Safari 启用擦除(scrubbing)支持(Chrome 和 Firefox 原生支持此特性) [NgClass](api/common/NgClass) on SVG elements [NgClass](api/common/NgClass)
+
+ on SVG elements 在 SVG 元素上应用 [NgClass](api/common/NgClass) [Http](guide/http) when sending and receiving binary data [Http](guide/http)
+
+ when sending and receiving binary data 用 [Http](guide/http) 发送和接收二进制数据 根据 map 中的 value 是否为真,来决定该元素上是否出现与 name 对应的 CSS 类。右侧的表达式应该返回一个形如 Allows you to assign styles to an HTML element using CSS. You can use CSS directly, as in the first example, or you can call a method from the component.` and `
`和`
-The [**Angular CLI**](https://cli.angular.io/) produces a new project with the following minimal `AppModule`.
-You evolve this module as your application grows.
+An NgModule describes how the application parts fit together.
+Every application has at least one Angular module, the _root_ module
+that you bootstrap to launch the application.
+By convention, it is usually called `AppModule`.
+If you use the CLI to generate an app, the default `AppModule` is as follows:
-[开发环境](guide/setup)讲解了如何使用下面这个最小的`AppModule`来创建一个新项目。
-这个模块随着应用的成长而演变。
-
+
+
+
+ Browser
+
+
+
+ Supported versions
+
+
+
+
+
+
+
Chrome
-
+
-
+
+
+
+
+
+
+
+
Firefox
-
+
-
+
+ latest
+
+
+
+
+
Edge
-
+
-
+
+ 2 most recent major versions
+
+
+
+
IE
-
-
-
- Safari
-
-
-
- iOS
-
-
-
- Android
-
-
-
+
+
+ 11
+
10
9
+
+
+
-
-
IE Mobile
-
-
-
-
-
+
-
-
-
-
-
-
-
-
- 14
-
-
11
-
-
- 10
-
-
-
- 10
-
-
-
- Nougat (7.0)
-
-
Marshmallow (6.0)
-
- 11
-
-
+
+ Safari
+
+
+ 2 most recent major versions
+
+
-
-
+
-
+ iOS
-
+ 2 most recent major versions
-
-
- 13
-
-
-
- 10
-
-
-
- 9
-
-
-
- 9
-
-
-
- Lollipop
-
-
(5.0, 5.1)
-
-
-
-
-
-
-
-
-
+ Android
-
+ Nougat (7.0)
-
-
Marshmallow (6.0)
Lollipop (5.0, 5.1)
KitKat (4.4)
-
-
-
-
- 9
-
-
-
- 8
-
-
-
- 8
-
-
-
- KitKat
-
-
(4.4)
-
-
-
-
-
-
-
+
@@ -261,26 +162,23 @@ This file incorporates the mandatory and many of the optional polyfills as JavaS
这个文件把强制的和很多可选的填充脚本组织成 JavaScript 的 `import` 语句。
-The npm packages for the _mandatory_ polyfills (such as `zone.js`) were installed automatically for you when you created your project and
-their corresponding `import` statements are ready to go.
-You probably won't touch these.
+The npm packages for the _mandatory_ polyfills (such as `zone.js`) were installed automatically for you when you created your project and their corresponding `import` statements are ready to go. You probably won't touch these.
**强制性** 填充脚本(如`zone.js`)的npm 包在创建工程时就已经自动安装了,相应的 `import` 语句也都加好了。我们一般不用动它们。
-But if you need an optional polyfill, you'll have to install its npm package with `npm` or `yarn`.
-For example, [if you need the web animations polyfill](http://caniuse.com/#feat=web-animation),
-you could install it with either of the following commands:
+But if you need an optional polyfill, you'll have to install its npm package.
+For example, [if you need the web animations polyfill](http://caniuse.com/#feat=web-animation), you could install it with `npm`, using the following command (or the `yarn` equivalent):
但是如果要用一个可选的填充库,就要通过 `npm` 或 `yarn` 来安装它们的 npm 包了。
比如,[如果你需要 web 动画的填充脚本](http://caniuse.com/#feat=web-animation),就要通过下列命令之一来安装它:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 7
-
-
-
- 7
-
-
-
- Jelly Bean
-
-
(4.1, 4.2, 4.3)
-
-
-
-
-
[ES7/reflect](guide/browser-support#core-es7-reflect) (JIT only)
+
@@ -375,8 +274,8 @@ These are the polyfills required to run an Angular application on each supported
-
[ES6](guide/browser-support#core-es6)
+
@@ -389,7 +288,6 @@ These are the polyfills required to run an Angular application on each supported
-
[ES6
@@ -408,7 +306,7 @@ Some features of Angular may require additional polyfills.
有些 Angular 特性可能需要额外的填充库。
For example, the animations library relies on the standard web animation API, which is only available in Chrome and Firefox today.
-You'll need a polyfill to use animations in other browsers.
+(note that the dependency of web-animations-js in Angular is only necessary if `AnimationBuilder` is used.)
例如,动画库依赖于标准的 web 动画 API,目前它只在 Chrome 和 Firefox 上可用。你可能需要一个填充库来在其它浏览器上使用动画功能。
@@ -448,7 +346,8 @@ Here are the features which may require additional polyfills:
classList](guide/browser-support#classlist)
- [JIT compilation](guide/aot-compiler).
+ [JIT compilation](guide/aot-compiler).
+
Required to reflect for metadata.
[JIT 编译](guide/aot-compiler) 需要 reflect 来提供元数据。
@@ -458,13 +357,11 @@ Here are the features which may require additional polyfills:
[ES7/reflect](guide/browser-support#core-es7-reflect)
-
- All current browsers.
- Enabled by default.
- Can remove If you always use AOT and only use Angular decorators.
+ All current browsers. Enabled by default.
+ Can remove if you always use AOT and only use Angular decorators.
默认对目前的所有浏览器都启用了。如果总是使用 AOT 模式,并且只使用 Angular 自带的装饰器,那么可以移除它。
@@ -480,22 +377,25 @@ Here are the features which may require additional polyfills:
[动画](guide/animations)
+
Only if `Animation Builder` is used within the application--standard
+ animation support in Angular doesn't require any polyfills (as of NG6).
+
+
只有在应用中用到了 `Animation Builder` 时才需要;Angular 标准的动画支持是不需要任何填充库的(截至 NG6)。
+
-
[Web Animations](guide/browser-support#web-animations)
[Web 动画](guide/browser-support#web-animations)
-
- All but Chrome and Firefox
@@ -504,17 +404,24 @@ Here are the features which may require additional polyfills:
Not supported in IE9
+
- If you use the following deprecated i18n pipes: [date](api/common/DeprecatedDatePipe), [currency](api/common/DeprecatedCurrencyPipe), [decimal](api/common/DeprecatedDecimalPipe) and [percent](api/common/DeprecatedPercentPipe)
-
+ If you use the following deprecated i18n pipes:
+
如果你使用下列已废弃的i18n管道:
- [date](api/common/DeprecatedDatePipe)、[currency](api/common/DeprecatedCurrencyPipe)、[decimal](api/common/DeprecatedDecimalPipe) 和 [percent](api/common/DeprecatedPercentPipe)
+
+ [date](api/common/DeprecatedDatePipe),
+
+ [currency](api/common/DeprecatedCurrencyPipe),
+
+ [decimal](api/common/DeprecatedDecimalPipe),
+
+ [percent](api/common/DeprecatedPercentPipe)
-
[Intl API](guide/browser-support#intl)
+
@@ -530,15 +437,17 @@ Here are the features which may require additional polyfills:
-
-
[classList](guide/browser-support#classlist)
+
@@ -551,7 +460,9 @@ Here are the features which may require additional polyfills:
-
[Typed Array](guide/browser-support#typedarray)
+
[Blob](guide/browser-support#blob)
+
[FormData](guide/browser-support#formdata)
+
@@ -575,7 +489,9 @@ Here are the features which may require additional polyfills:
### Suggested polyfills ##
+
### 建议的填充库 ##
+
Below are the polyfills which are used to test the framework itself. They are a good starting point for an application.
下表中是用来测试框架本身的填充库,它们是应用程序的优质起点。
@@ -628,6 +544,7 @@ Below are the polyfills which are used to test the framework itself. They are a
ES7/reflect
+
@@ -643,7 +560,9 @@ Below are the polyfills which are used to test the framework itself. They are a
+
ES6
+
@@ -659,7 +578,9 @@ Below are the polyfills which are used to test the framework itself. They are a
+
classList
+
@@ -683,7 +604,9 @@ Below are the polyfills which are used to test the framework itself. They are a
+
Intl
+
@@ -699,7 +622,7 @@ Below are the polyfills which are used to test the framework itself. They are a
- Web Animations
+ Web Animations
@@ -715,7 +638,9 @@ Below are the polyfills which are used to test the framework itself. They are a
+
Typed Array
+
@@ -731,7 +656,9 @@ Below are the polyfills which are used to test the framework itself. They are a
+
Blob
+
@@ -747,7 +674,9 @@ Below are the polyfills which are used to test the framework itself. They are a
+
+
FormData
+
@@ -763,7 +692,6 @@ Below are the polyfills which are used to test the framework itself. They are a
-
\* Figures are for minified and gzipped code,
computed with the closure compiler.
@@ -772,7 +700,7 @@ computed with the closure co
## 不使用 CLI 的用户的填充库
-If you aren't using the CLI, you should add your polyfill scripts directly to the host web page (`index.html`), perhaps like this.
+If you are not using the CLI, you should add your polyfill scripts directly to the host web page (`index.html`), perhaps like this.
如果你不使用 CLI,就要直接把填充库添加到宿主页(`index.html`)中,就像这样:
@@ -780,10 +708,24 @@ If you aren't using the CLI, you should add your polyfill scripts directly to th
<!-- pre-zone polyfills -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/web-animations-js/web-animations.min.js"></script>
+ <script>
+ /**
+ * you can configure some zone flags which can disable zone interception for some
+ * asynchronous activities to improve startup performance - use these options only
+ * if you know what you are doing as it could result in hard to trace down bugs..
+ */
+ // __Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
+ // __Zone_disable_on_property = true; // disable patch onProperty such as onclick
+ // __zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
+ /*
+ * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
+ * with the following flag, it will bypass `zone.js` patch for IE/Edge
+ */
+ // __Zone_enable_cross_context_check = true;
+ </script>
<!-- zone.js required by Angular -->
<script src="node_modules/zone.js/dist/zone.js"></script>
<!-- application polyfills -->
-
diff --git a/aio/content/guide/change-log.md b/aio/content/guide/change-log.md
index 2f7425e5d8..fa1497c134 100644
--- a/aio/content/guide/change-log.md
+++ b/aio/content/guide/change-log.md
@@ -174,7 +174,7 @@ HTTP guide.
## 测试:添加了组件测试的plunker范例 (2016-12-02)
Added two plunkers that each test _one simple component_ so you can write a component test plunker of your own:
declarations
of this module.
{class-name: true/false}
的 map。
+
+<div [ngStyle]="{'property': 'value'}">
<div [ngStyle]="dynamicStyles()">
+
diff --git a/aio/content/guide/comparing-observables.md b/aio/content/guide/comparing-observables.md
new file mode 100644
index 0000000000..9cb663cd56
--- /dev/null
+++ b/aio/content/guide/comparing-observables.md
@@ -0,0 +1,313 @@
+# Observables compared to other techniques
+
+You can often use observables instead of promises to deliver values asynchronously. Similarly, observables can take the place of event handlers. Finally, because observables deliver multiple values, you can use them where you might otherwise build and operate on arrays.
+
+Observables behave somewhat differently from the alternative techniques in each of these situations, but offer some significant advantages. Here are detailed comparisons of the differences.
+
+## Observables compared to promises
+
+Observables are often compared to promises. Here are some key differences:
+
+* Observables are declarative; computation does not start until subscription. Promises execute immediately on creation. This makes observables useful for defining recipes that can be run whenever you need the result.
+
+* Observables provide many values. Promises provide one. This makes observables useful for getting multiple values over time.
+
+* Observables differentiate between chaining and subscription. Promises only have `.then()` clauses. This makes observables useful for creating complex transformation recipes to be used by other part of the system, without causing the work to be executed.
+
+* Observables `subscribe()` is responsible for handling errors. Promises push errors to the child promises. This makes observables useful for centralized and predictable error handling.
+
+
+### Creation and subscription
+
+* Observables are not executed until a consumer subcribes. The `subscribe()` executes the defined behavior once, and it can be called again. Each subscription has its own computation. Resubscription causes recomputation of values.
+
+
+
+
+## Observables compared to events API
+
+Observables are very similar to event handlers that use the events API. Both techniques define notification handlers, and use them to process multiple values delivered over time. Subscribing to an observable is equivalent to adding an event listener. One significant difference is that you can configure an observable to transform an event before passing the event to the handler.
+
+Using observables to handle events and asynchronous operations can have the advantage of greater consistency in contexts such as HTTP requests.
+
+Here are some code samples that illustrate how the same kind of operation is defined using observables and the events API.
+
+
+ Operation
+ Observable
+ Promise
+
+
+
+ Creation
+
+
+ new Observable((observer) => {
+ observer.next(123);
+});
+
+
+ new Promise((resolve, reject) => {
+ resolve(123);
+});
+
+
+ Transform
+
+ obs.map((value) => value * 2 );
+ promise.then((value) => value * 2);
+
+ Subscribe
+
+
+ sub = obs.subscribe((value) => {
+ console.log(value)
+});
+
+
+ promise.then((value) => {
+ console.log(value);
+});
+
+
+Unsubscribe
+
+ sub.unsubscribe();
Implied by promise resolution.
+
+
+
+
+## Observables compared to arrays
+
+An observable produces values over time. An array is created as a static set of values. In a sense, observables are asynchronous where arrays are synchronous. In the following examples, ➞ implies asynchronous value delivery.
+
+
+ Observable
+ Events API
+
+
+
+ Creation & cancellation
+
+
+ // Setup
+let clicks$ = fromEvent(buttonEl, ‘click’);
+// Begin listening
+let subscription = clicks$
+ .subscribe(e => console.log(‘Clicked’, e))
+// Stop listening
+subscription.unsubscribe();
+
+
+ function handler(e) {
+ console.log(‘Clicked’, e);
+}
+
+// Setup & begin listening
+button.addEventListener(‘click’, handler);
+// Stop listening
+button.removeEventListener(‘click’, handler);
+
+
+
+ Subscription
+
+
+ observable.subscribe(() => {
+ // notification handlers here
+});
+
+
+ element.addEventListener(eventName, (event) => {
+ // notification handler here
+});
+
+
+Configuration
+ Listen for keystrokes, but provide a stream representing the value in the input.
+
+ fromEvent(inputEl, 'keydown').pipe(
+ map(e => e.target.value)
+);
+ Does not support configuration.
+
+ element.addEventListener(eventName, (event) => {
+ // Cannot change the passed Event into another
+ // value before it gets to the handler
+});
+
+
+
+
+
diff --git a/aio/content/guide/component-styles.md b/aio/content/guide/component-styles.md
index e39b4d5707..ad421a15a6 100644
--- a/aio/content/guide/component-styles.md
+++ b/aio/content/guide/component-styles.md
@@ -16,19 +16,15 @@ with components, enabling a more modular design than regular stylesheets.
This page describes how to load and apply these component styles.
-在本章中,我们将学到如何加载和使用这些*组件样式*。
-
-You can run the
+ Observable
+ Array
+
+
+
+ Given
+
+
+ obs: ➞1➞2➞3➞5➞7
+ obsB: ➞'a'➞'b'➞'c'
+
+
+ arr: [1, 2, 3, 5, 7]
+ arrB: ['a', 'b', 'c']
+
+
+
+ concat()
+
+ obs.concat(obsB)
+ ➞1➞2➞3➞5➞7➞'a'➞'b'➞'c'
+
+
+ arr.concat(arrB)
+ [1,2,3,5,7,'a','b','c']
+
+
+
+ filter()
+
+ obs.filter((v) => v>3)
+ ➞5➞7
+
+
+ arr.filter((v) => v>3)
+ [5, 7]
+
+
+
+ find()
+
+ obs.find((v) => v>3)
+ ➞5
+
+
+ arr.find((v) => v>10)
+ 5
+
+
+
+ findIndex()
+
+ obs.findIndex((v) => v>3)
+ ➞3
+
+
+ arr.findIndex((v) => v>3)
+ 3
+
+
+
+ forEach()
+
+ obs.forEach((v) => {
+ console.log(v);
+})
+1
+2
+3
+4
+5
+
+
+ arr.forEach((v) => {
+ console.log(v);
+})
+1
+2
+3
+4
+5
+
+
+
+ map()
+
+ obs.map((v) => -v)
+ ➞-1➞-2➞-3➞-5➞-7
+
+
+ arr.map((v) => -v)
+ [-1, -2, -3, -5, -7]
+
+
+
+ reduce()
+
+ obs.scan((s,v)=> s+v, 0)
+ ➞1➞3➞6➞11➞18
+
+
+ arr.reduce((s,v) => s+v, 0)
+ 18
+ ` elements, from the host element down
-through this component to all of its child elements in the DOM.
+The following example targets all `
` elements, from the host element down
+through this component to all of its child elements in the DOM.
在这个例子中,我们以所有的`
`元素为目标,从宿主元素到当前元素再到 DOM 中的所有子元素:
@@ -226,7 +220,7 @@ CSS标准中用于 "刺穿Shadow DOM" 的组合器已经被废弃,并将[这
## 把样式加载进组件中
-There are several ways to add styles to a component:
+There are several ways to add styles to a component:
有几种方式把样式加入组件:
@@ -290,8 +284,8 @@ to a component's `@Component` decorator: