Compare commits
197 Commits
Author | SHA1 | Date | |
---|---|---|---|
0e95a20576 | |||
9c7428e7ad | |||
d3044271dc | |||
4348c472d6 | |||
2ec05415e2 | |||
188e9ceb1f | |||
de7b554a14 | |||
1d252a559b | |||
bff5c24ed2 | |||
53197de80c | |||
12757474e6 | |||
057423e3e7 | |||
7a1b8763b2 | |||
cbd420656d | |||
f33307badb | |||
b00588a240 | |||
fb0d93d2c1 | |||
cc0fd6036d | |||
682034fcc0 | |||
0475b8d686 | |||
6be6125c5c | |||
1b7b64ae18 | |||
d284fa6bd2 | |||
8e4dca0ddf | |||
006a43f951 | |||
5469b6f64b | |||
926367150a | |||
14ff340e93 | |||
c8e750745a | |||
6b8f2da93e | |||
352219eafb | |||
e8a8770eee | |||
f536261639 | |||
2d06693560 | |||
315d95c747 | |||
5c5b62cc86 | |||
479f773bb3 | |||
629c83588d | |||
d96ba0ffd9 | |||
30700035b3 | |||
8c6d6b85db | |||
0c10b57749 | |||
fe1c0d7a0c | |||
dc053859ee | |||
4d532df52b | |||
5eb540cf34 | |||
7697650edc | |||
4517b8e618 | |||
3abc4c9c54 | |||
1d6333891c | |||
4d4e85b708 | |||
28104828d5 | |||
77f531b6f7 | |||
3041240cbc | |||
257ac83095 | |||
bc93d47129 | |||
3f61071638 | |||
ea571aa9d1 | |||
40cd0371d2 | |||
8356577670 | |||
45d3c8093b | |||
e7eec2e44b | |||
c44b93253c | |||
cd444bc2ba | |||
e9ae26a272 | |||
f9856974e3 | |||
b3c6409763 | |||
4c3e9a32d2 | |||
2700952040 | |||
6d92c99c49 | |||
7cefb3efd4 | |||
1c0ab3468d | |||
b5ede01c09 | |||
98b1a9dcfe | |||
c277c198d2 | |||
b7d7609872 | |||
415e3e06ed | |||
0f7a850699 | |||
1e2525b8a7 | |||
bc9f534bf4 | |||
ea2a3ca705 | |||
802e996e64 | |||
aa7dd1267b | |||
91916e7113 | |||
0e92f1eee5 | |||
4ac3b2e2bd | |||
20ce134961 | |||
c01f3409f3 | |||
71580c8e37 | |||
e58f8b7be0 | |||
046c96a3f1 | |||
00e6569e0f | |||
5dbf9f721b | |||
c63bc02846 | |||
2f3308e4f0 | |||
cc5e4fb93f | |||
3ab9947c7f | |||
b1f92db22b | |||
bda1e52b50 | |||
1084ebc091 | |||
5a3af00398 | |||
7a088af3ff | |||
3e8d8ec2f5 | |||
d4ea7f1f7e | |||
23096501e2 | |||
023874426e | |||
aeffcdd417 | |||
6d7d7c77e3 | |||
8da6c369e5 | |||
d0f2bae62b | |||
062af7a725 | |||
9d1d70a563 | |||
5f908eedbf | |||
a3eac19831 | |||
cace4dea64 | |||
a012ffbd5b | |||
2065149d73 | |||
44e604b131 | |||
4503b28295 | |||
f8fcea333f | |||
a09782b8ac | |||
bfeceb3d3e | |||
1a5735d5c0 | |||
43d4446ec0 | |||
91edfb8be0 | |||
9d0a6554a3 | |||
8fff438767 | |||
b2ae08f272 | |||
c78542f124 | |||
b52c97cf70 | |||
929739c736 | |||
85bde4ff90 | |||
5b5b8254b1 | |||
ac8871fb7f | |||
6b2b1eae9d | |||
b3f096219f | |||
224d9dcd4a | |||
31a0c2a6c2 | |||
c251a5a4d1 | |||
81e571b908 | |||
80a9de0a57 | |||
d1e2ac86fd | |||
9a0d326f4f | |||
ce3024017a | |||
c8adef2dab | |||
778e1c2602 | |||
35bfa1437f | |||
4d83078cd2 | |||
64d005de05 | |||
0c822b75f9 | |||
e0a9cfb5e2 | |||
f8dff83d4b | |||
e411cd124a | |||
df4e85907c | |||
1498dc2dca | |||
abfde44afb | |||
eb9d431487 | |||
9060fb7031 | |||
7fbe547f78 | |||
cda6a215f2 | |||
a8430db45d | |||
5e2bf292e5 | |||
efded24527 | |||
30ac643d1d | |||
d9725016ad | |||
3f94759b14 | |||
9a46420aaf | |||
6a11d7e2a0 | |||
4fd9988251 | |||
a4fcd07792 | |||
078a928fab | |||
5d90aede4e | |||
658a18cdab | |||
6d240cf687 | |||
dca176e232 | |||
6c4845515b | |||
c2ce832f65 | |||
c726d27331 | |||
c4b7862e1b | |||
39472e102b | |||
1fafc5ca18 | |||
07a26647ac | |||
817821e553 | |||
398db3e9f0 | |||
d5fa4dc146 | |||
0ae3518fa9 | |||
e0f9a1b3f3 | |||
2604f429c7 | |||
ecada17ad4 | |||
fa3751ec9e | |||
f85a969219 | |||
d0a1e42e50 | |||
4f14a09895 | |||
8d28fe9df9 | |||
6715f056b0 | |||
32c018cbfe | |||
a403c4f7f5 |
3
.bazelignore
Normal file
3
.bazelignore
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
aio/node_modules
|
@ -24,6 +24,10 @@ build --symlink_prefix=/
|
||||
# Performance: avoid stat'ing input files
|
||||
build --watchfs
|
||||
|
||||
# Turn off legacy external runfiles
|
||||
run --nolegacy_external_runfiles
|
||||
test --nolegacy_external_runfiles
|
||||
|
||||
###############################
|
||||
# Release support #
|
||||
###############################
|
||||
@ -57,6 +61,6 @@ test --experimental_ui
|
||||
################################
|
||||
# Temporary Settings for Ivy #
|
||||
################################
|
||||
# to determine if the compiler used should be Ivy or ViewEngine one can use `--define=compile=local` on
|
||||
# to determine if the compiler used should be Ivy or ViewEngine one can use `--define=compile=local` on
|
||||
# any bazel target. This is a temporary flag until codebase is permanently switched to Ivy.
|
||||
build --define=compile=legacy
|
||||
build --define=compile=legacy
|
@ -13,7 +13,7 @@ a GitHub token that enables publishing snapshots.
|
||||
|
||||
To create the github_token file, we take this approach:
|
||||
- Find the angular-builds:token in http://valentine
|
||||
- Go inside the ngcontainer docker image so you use the same version of openssl as we will at runtime: `docker run --rm -it angular/ngcontainer`
|
||||
- Go inside the CircleCI default docker image so you use the same version of openssl as we will at runtime: `docker run --rm -it circleci/node:10.12`
|
||||
- echo "https://[token]:@github.com" > credentials
|
||||
- openssl aes-256-cbc -e -in credentials -out .circleci/github_token -k $KEY
|
||||
- If needed, base64-encode the result so you can copy-paste it out of docker: `base64 github_token`
|
@ -7,41 +7,47 @@
|
||||
# To validate changes, use an online parser, eg.
|
||||
# http://yaml-online-parser.appspot.com/
|
||||
|
||||
# Variables
|
||||
|
||||
## 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.6.0
|
||||
var_2: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.6.0
|
||||
# Note that the browser docker image comes with Chrome and Firefox preinstalled. This is just
|
||||
# needed for jobs that run tests without Bazel. Bazel runs tests with browsers that will be
|
||||
# fetched by the Webtesting rules. Therefore for jobs that run tests with Bazel, we don't need a
|
||||
# docker image with browsers pre-installed.
|
||||
# **NOTE**: If you change the version of the docker images, also change the `cache_key` suffix.
|
||||
var_1: &default_docker_image circleci/node:10.12
|
||||
var_2: &browsers_docker_image circleci/node:10.12-browsers
|
||||
var_3: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-node-10.12
|
||||
|
||||
# Define common ENV vars
|
||||
var_3: &define_env_vars
|
||||
run: echo "export PROJECT_ROOT=$(pwd)" >> $BASH_ENV
|
||||
|
||||
# See remote cache documentation in /docs/BAZEL.md
|
||||
var_4: &setup-bazel-remote-cache
|
||||
var_4: &define_env_vars
|
||||
run:
|
||||
name: Start up bazel remote cache proxy
|
||||
command: ~/bazel-remote-proxy -backend circleci://
|
||||
background: true
|
||||
name: Define environment variables
|
||||
command: ./.circleci/env.sh
|
||||
|
||||
var_5: &setup_bazel_remote_execution
|
||||
run:
|
||||
name: "Setup bazel RBE remote execution"
|
||||
command: openssl aes-256-cbc -d -in .circleci/gcp_token -k "${CIRCLE_PROJECT_REPONAME}" -out /home/circleci/.gcp_credentials && echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/circleci/.gcp_credentials" >> $BASH_ENV && sudo bash -c "cat .circleci/rbe-bazel.rc >> /etc/bazel.bazelrc"
|
||||
command: openssl aes-256-cbc -d -in .circleci/gcp_token -k "$CI_REPO_NAME" -out /home/circleci/.gcp_credentials && echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/circleci/.gcp_credentials" >> $BASH_ENV && sudo bash -c "cat .circleci/rbe-bazel.rc >> /etc/bazel.bazelrc"
|
||||
|
||||
# Settings common to each job
|
||||
anchor_1: &job_defaults
|
||||
var_6: &job_defaults
|
||||
working_directory: ~/ng
|
||||
docker:
|
||||
- image: *docker_image
|
||||
- image: *default_docker_image
|
||||
|
||||
# After checkout, rebase on top of master.
|
||||
# Similar to travis behavior, but not quite the same.
|
||||
# See https://discuss.circleci.com/t/1662
|
||||
anchor_2: &post_checkout
|
||||
post: git pull --ff-only origin "refs/pull/${CIRCLE_PULL_REQUEST//*pull\//}/merge"
|
||||
var_7: &post_checkout
|
||||
post: git pull --ff-only origin "refs/pull/${CI_PULL_REQUEST//*pull\//}/merge"
|
||||
|
||||
var_8: &yarn_install
|
||||
run:
|
||||
name: Running Yarn install
|
||||
command: yarn install --frozen-lockfile --non-interactive
|
||||
|
||||
var_9: &setup_circleci_bazel_config
|
||||
run:
|
||||
name: Setting up CircleCI bazel configuration
|
||||
command: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
@ -51,43 +57,38 @@ jobs:
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *setup_circleci_bazel_config
|
||||
- *yarn_install
|
||||
|
||||
# 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: 'yarn buildifier -mode=check ||
|
||||
(echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)'
|
||||
# Run the skylark linter to check our Bazel rules
|
||||
- run: 'yarn skylint ||
|
||||
(echo -e "\n.bzl files have lint errors. Please run ''yarn skylint''"; exit 1)'
|
||||
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
|
||||
- run: yarn install --frozen-lockfile --non-interactive
|
||||
- run: ./node_modules/.bin/gulp lint
|
||||
|
||||
test:
|
||||
<<: *job_defaults
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- *define_env_vars
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *setup_circleci_bazel_config
|
||||
- *yarn_install
|
||||
|
||||
- run: bazel info release
|
||||
- run: bazel run @nodejs//:yarn
|
||||
# Use bazel query so that we explicitly ask for all buildable targets to be built as well
|
||||
# This avoids waiting for the slowest build target to finish before running the first test
|
||||
# See https://github.com/bazelbuild/bazel/issues/4257
|
||||
# NOTE: Angular developers should typically just bazel build //packages/... or bazel test //packages/...
|
||||
# Setup remote execution and run RBE-compatible tests.
|
||||
- *setup_bazel_remote_execution
|
||||
- run: bazel query --output=label //... | xargs bazel test --build_tag_filters=-ivy-only --test_tag_filters=-manual,-ivy-only,-local
|
||||
- run: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only,-local
|
||||
# Now run RBE incompatible tests locally.
|
||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
- run: bazel query --output=label //... | xargs bazel test --build_tag_filters=-ivy-only,local --test_tag_filters=-manual,-ivy-only,local
|
||||
- run: yarn bazel test //... --build_tag_filters=-ivy-only,local --test_tag_filters=-ivy-only,local
|
||||
|
||||
# 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.
|
||||
@ -113,34 +114,166 @@ jobs:
|
||||
paths:
|
||||
- "node_modules"
|
||||
- "~/bazel_repository_cache"
|
||||
|
||||
# Temporary job to test what will happen when we flip the Ivy flag to true
|
||||
test_ivy_jit:
|
||||
<<: *job_defaults
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- *define_env_vars
|
||||
# don't run this job on the patch branch (to preserve resources)
|
||||
- run: circleci step halt
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
|
||||
- run: bazel run @yarn//:yarn
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *setup_circleci_bazel_config
|
||||
- *yarn_install
|
||||
- *setup_bazel_remote_execution
|
||||
- run: bazel query --output=label //... | xargs bazel test --define=compile=jit --build_tag_filters=ivy-jit --test_tag_filters=-manual,ivy-jit
|
||||
|
||||
- run: yarn test-ivy-jit //...
|
||||
|
||||
test_ivy_aot:
|
||||
<<: *job_defaults
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- *define_env_vars
|
||||
# don't run this job on the patch branch (to preserve resources)
|
||||
- run: circleci step halt
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
|
||||
- run: bazel run @yarn//:yarn
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *setup_circleci_bazel_config
|
||||
- *yarn_install
|
||||
- *setup_bazel_remote_execution
|
||||
- run: bazel query --output=label //... | xargs bazel test --define=compile=local --build_tag_filters=ivy-local --test_tag_filters=-manual,ivy-local
|
||||
|
||||
# This job should only be run on PR builds, where `CIRCLE_PR_NUMBER` is defined.
|
||||
- run: yarn test-ivy-aot //...
|
||||
|
||||
test_aio:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
# Needed because the AIO tests and the PWA score test depend on Chrome being available.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
# Build aio
|
||||
- run: yarn --cwd aio build --progress=false
|
||||
# Lint the code
|
||||
- run: yarn --cwd aio lint
|
||||
# Run PWA-score tests
|
||||
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
|
||||
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
||||
# Check the bundle sizes.
|
||||
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
|
||||
- run: yarn --cwd aio payload-size
|
||||
# Run unit tests
|
||||
- run: yarn --cwd aio test --watch=false
|
||||
# Run e2e tests
|
||||
- run: yarn --cwd aio e2e
|
||||
# Run unit tests for Firebase redirects
|
||||
- run: yarn --cwd aio redirects-test
|
||||
|
||||
deploy_aio:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
# Needed because before deploying the deploy-production script runs the PWA score tests.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
# Deploy angular.io to production (if necessary)
|
||||
- run: setPublicVar CI_STABLE_BRANCH "$(npm info @angular/core dist-tags.latest | sed -r 's/^\s*([0-9]+\.[0-9]+)\.[0-9]+.*$/\1.x/')"
|
||||
- run: yarn --cwd aio deploy-production
|
||||
|
||||
test_aio_local:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
# Needed because the AIO tests and the PWA score test depend on Chrome being available.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
- *define_env_vars
|
||||
# Build aio (with local Angular packages)
|
||||
- run: yarn --cwd aio build-local --progress=false
|
||||
# Run PWA-score tests
|
||||
# (Run before unit and e2e tests, which destroy the `dist/` directory.)
|
||||
- run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE
|
||||
# Run unit tests
|
||||
- run: yarn --cwd aio test --watch=false
|
||||
# Run e2e tests
|
||||
- run: yarn --cwd aio e2e
|
||||
|
||||
test_aio_tools:
|
||||
<<: *job_defaults
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
- *define_env_vars
|
||||
# Install
|
||||
- run: yarn --cwd aio install --frozen-lockfile --non-interactive
|
||||
- run: yarn --cwd aio extract-cli-command-docs
|
||||
# Run tools tests
|
||||
- run: yarn --cwd aio tools-test
|
||||
- run: ./aio/aio-builds-setup/scripts/test.sh
|
||||
|
||||
test_docs_examples_0:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
# Needed because the example e2e tests depend on Chrome.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
- *define_env_vars
|
||||
# Install root
|
||||
- *yarn_install
|
||||
# Install aio
|
||||
- run: yarn --cwd aio install --frozen-lockfile --non-interactive
|
||||
# Run examples tests
|
||||
- run: yarn --cwd aio example-e2e --setup --local --shard=0/2
|
||||
|
||||
test_docs_examples_1:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
# Needed because the example e2e tests depend on Chrome.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
- *define_env_vars
|
||||
# Install root
|
||||
- *yarn_install
|
||||
# Install aio
|
||||
- run: yarn --cwd aio install --frozen-lockfile --non-interactive
|
||||
# Run examples tests
|
||||
- run: yarn --cwd aio example-e2e --setup --local --shard=1/2
|
||||
|
||||
# This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`.
|
||||
aio_preview:
|
||||
<<: *job_defaults
|
||||
environment:
|
||||
@ -150,28 +283,31 @@ jobs:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- run: yarn install --frozen-lockfile --non-interactive
|
||||
- run: ./aio/scripts/build-artifacts.sh $AIO_SNAPSHOT_ARTIFACT_PATH $CIRCLE_PR_NUMBER $CIRCLE_SHA1
|
||||
- *define_env_vars
|
||||
- *yarn_install
|
||||
- run: ./aio/scripts/build-artifacts.sh $AIO_SNAPSHOT_ARTIFACT_PATH $CI_PULL_REQUEST $CI_COMMIT
|
||||
- store_artifacts:
|
||||
path: *aio_preview_artifact_path
|
||||
# The `destination` needs to be kept in synch with the value of
|
||||
# `AIO_ARTIFACT_PATH` in `aio/aio-builds-setup/Dockerfile`
|
||||
destination: aio/dist/aio-snapshot.tgz
|
||||
|
||||
# This job should only be run on PR builds, where `CIRCLE_PR_NUMBER` is defined.
|
||||
# This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`.
|
||||
test_aio_preview:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
# Needed because the test-preview script runs e2e tests and the PWA score test with Chrome.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- run: yarn install --cwd aio --frozen-lockfile --non-interactive
|
||||
- run:
|
||||
name: Wait for preview and run tests
|
||||
command: |
|
||||
source "./scripts/ci/env.sh" print
|
||||
xvfb-run --auto-servernum node aio/scripts/test-preview.js $CIRCLE_PR_NUMBER $CIRCLE_SHA1 $AIO_MIN_PWA_SCORE
|
||||
command: node aio/scripts/test-preview.js $CI_PULL_REQUEST $CI_COMMIT $CI_AIO_MIN_PWA_SCORE
|
||||
|
||||
# This job exists only for backwards-compatibility with old scripts and tests
|
||||
# that rely on the pre-Bazel dist/packages-dist layout.
|
||||
@ -184,12 +320,15 @@ jobs:
|
||||
<<: *job_defaults
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- *define_env_vars
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
- run: bazel run @nodejs//:yarn
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- *setup_circleci_bazel_config
|
||||
- *yarn_install
|
||||
- *setup_bazel_remote_execution
|
||||
|
||||
- run: scripts/build-packages-dist.sh
|
||||
|
||||
# Save the npm packages from //packages/... for other workflow jobs to read
|
||||
@ -199,7 +338,7 @@ jobs:
|
||||
paths:
|
||||
- packages-dist
|
||||
- packages-dist-ivy-jit
|
||||
- packages-dist-ivy-local
|
||||
- packages-dist-ivy-aot
|
||||
|
||||
# We run the integration tests outside of Bazel for now.
|
||||
# They are a separate workflow job so that they can be easily re-run.
|
||||
@ -209,35 +348,41 @@ jobs:
|
||||
# See comments inside the integration/run_tests.sh script.
|
||||
integration_test:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
# Needed because the integration tests expect Chrome to be installed (e.g cli-hello-world)
|
||||
- image: *browsers_docker_image
|
||||
# Note: we run Bazel in one of the integration tests, and it can consume >2G
|
||||
# of memory. Together with the system under test, this can exhaust the RAM
|
||||
# on a 4G worker so we use a larger machine here too.
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- *define_env_vars
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
- run: xvfb-run --auto-servernum ./integration/run_tests.sh
|
||||
- *define_env_vars
|
||||
- run: ./integration/run_tests.sh
|
||||
|
||||
# This job updates the content of repos like github.com/angular/core-builds
|
||||
# for every green build on angular/angular.
|
||||
publish_snapshot:
|
||||
<<: *job_defaults
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- *define_env_vars
|
||||
# See below - ideally this job should not trigger for non-upstream builds.
|
||||
# But since it does, we have to check this condition.
|
||||
- run:
|
||||
name: Skip this job for Pull Requests and Fork builds
|
||||
# Note, `|| true` on the end makes this step always exit 0
|
||||
command: '[[
|
||||
-v CIRCLE_PR_NUMBER
|
||||
|| "$CIRCLE_PROJECT_USERNAME" != "angular"
|
||||
|| "$CIRCLE_PROJECT_REPONAME" != "angular"
|
||||
"$CI_PULL_REQUEST" != "false"
|
||||
|| "$CI_REPO_OWNER" != "angular"
|
||||
|| "$CI_REPO_NAME" != "angular"
|
||||
]] && circleci step halt || true'
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
# CircleCI has a config setting to force SSH for all github connections
|
||||
@ -251,16 +396,23 @@ jobs:
|
||||
|
||||
aio_monitoring:
|
||||
<<: *job_defaults
|
||||
docker:
|
||||
# This job needs Chrome to be globally installed because the tests run with Protractor
|
||||
# which does not load the browser through the Bazel webtesting rules.
|
||||
- image: *browsers_docker_image
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- *define_env_vars
|
||||
- run:
|
||||
name: Run tests against the deployed apps
|
||||
command: |
|
||||
source "./scripts/ci/env.sh" print
|
||||
xvfb-run --auto-servernum ./aio/scripts/test-production.sh $AIO_MIN_PWA_SCORE
|
||||
command: ./aio/scripts/test-production.sh $CI_AIO_MIN_PWA_SCORE
|
||||
- run:
|
||||
name: Notify caretaker about failure
|
||||
command: 'curl --request POST --header "Content-Type: application/json" --data "{\"text\":\":x: \`$CIRCLE_JOB\` job failed on build $CIRCLE_BUILD_NUM: $CIRCLE_BUILD_URL :scream:\"}" $CI_SECRET_SLACK_CARETAKER_WEBHOOK_URL'
|
||||
when: on_fail
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
@ -271,6 +423,22 @@ workflows:
|
||||
- test_ivy_jit
|
||||
- test_ivy_aot
|
||||
- build-packages-dist
|
||||
- test_aio
|
||||
- deploy_aio:
|
||||
requires:
|
||||
- test_aio
|
||||
- test_aio_local:
|
||||
requires:
|
||||
- build-packages-dist
|
||||
- test_aio_tools:
|
||||
requires:
|
||||
- build-packages-dist
|
||||
- test_docs_examples_0:
|
||||
requires:
|
||||
- build-packages-dist
|
||||
- test_docs_examples_1:
|
||||
requires:
|
||||
- build-packages-dist
|
||||
- aio_preview:
|
||||
# Only run on PR builds. (There can be no previews for non-PR builds.)
|
||||
filters:
|
||||
@ -293,6 +461,10 @@ workflows:
|
||||
- test_ivy_jit
|
||||
- test_ivy_aot
|
||||
- integration_test
|
||||
# Only publish if `aio`/`docs` tests using the locally built Angular packages pass
|
||||
- test_aio_local
|
||||
- test_docs_examples_0
|
||||
- test_docs_examples_1
|
||||
# Get the artifacts to publish from the build-packages-dist job
|
||||
# since the publishing script expects the legacy outputs layout.
|
||||
- build-packages-dist
|
||||
|
38
.circleci/env-helpers.inc.sh
Normal file
38
.circleci/env-helpers.inc.sh
Normal file
@ -0,0 +1,38 @@
|
||||
####################################################################################################
|
||||
# Helpers for defining environment variables for CircleCI.
|
||||
#
|
||||
# In CircleCI, each step runs in a new shell. The way to share ENV variables across steps is to
|
||||
# export them from `$BASH_ENV`, which is automatically sourced at the beginning of every step (for
|
||||
# the default `bash` shell).
|
||||
#
|
||||
# See also https://circleci.com/docs/2.0/env-vars/#using-bash_env-to-set-environment-variables.
|
||||
####################################################################################################
|
||||
|
||||
# Set and print an environment variable.
|
||||
#
|
||||
# Use this function for setting environment variables that are public, i.e. it is OK for them to be
|
||||
# visible to anyone through the CI logs.
|
||||
#
|
||||
# Usage: `setPublicVar <name> <value>`
|
||||
function setPublicVar() {
|
||||
setSecretVar $1 $2;
|
||||
echo "$1=$2";
|
||||
}
|
||||
|
||||
# Set (without printing) an environment variable.
|
||||
#
|
||||
# Use this function for setting environment variables that are secret, i.e. should not be visible to
|
||||
# everyone through the CI logs.
|
||||
#
|
||||
# Usage: `setSecretVar <name> <value>`
|
||||
function setSecretVar() {
|
||||
# WARNING: Secrets (e.g. passwords, access tokens) should NOT be printed.
|
||||
# (Keep original shell options to restore at the end.)
|
||||
local -r originalShellOptions=$(set +o);
|
||||
set +x -eu -o pipefail;
|
||||
|
||||
echo "export $1=\"${2:-}\";" >> $BASH_ENV;
|
||||
|
||||
# Restore original shell options.
|
||||
eval "$originalShellOptions";
|
||||
}
|
35
.circleci/env.sh
Executable file
35
.circleci/env.sh
Executable file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Load helpers and make them available everywhere (through `$BASH_ENV`).
|
||||
readonly envHelpersPath="`dirname $0`/env-helpers.inc.sh";
|
||||
source $envHelpersPath;
|
||||
echo "source $envHelpersPath;" >> $BASH_ENV;
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define PUBLIC environment variables for CircleCI.
|
||||
####################################################################################################
|
||||
setPublicVar PROJECT_ROOT "$(pwd)";
|
||||
setPublicVar CI_AIO_MIN_PWA_SCORE "95";
|
||||
# This is the branch being built; e.g. `pull/12345` for PR builds.
|
||||
setPublicVar CI_BRANCH "$CIRCLE_BRANCH";
|
||||
setPublicVar CI_COMMIT "$CIRCLE_SHA1";
|
||||
# `CI_COMMIT_RANGE` will only be available when `CIRCLE_COMPARE_URL` is also available,
|
||||
# i.e. on push builds (a.k.a. non-PR builds). That is fine, since we only need it in push builds.
|
||||
setPublicVar CI_COMMIT_RANGE "$(sed -r 's|^.*/([0-9a-f]+\.\.\.[0-9a-f]+)$|\1|i' <<< ${CIRCLE_COMPARE_URL:-})";
|
||||
setPublicVar CI_PULL_REQUEST "${CIRCLE_PR_NUMBER:-false}";
|
||||
setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME";
|
||||
setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME";
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define SECRET environment variables for CircleCI.
|
||||
####################################################################################################
|
||||
setSecretVar CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN "$AIO_DEPLOY_TOKEN";
|
||||
setSecretVar CI_SECRET_PAYLOAD_FIREBASE_TOKEN "$ANGULAR_PAYLOAD_TOKEN";
|
||||
# Defined in https://angular-team.slack.com/apps/A0F7VRE7N-circleci.
|
||||
setSecretVar CI_SECRET_SLACK_CARETAKER_WEBHOOK_URL "$SLACK_CARETAKER_WEBHOOK_URL";
|
||||
|
||||
|
||||
# Source `$BASH_ENV` to make the variables available immediately.
|
||||
source $BASH_ENV;
|
Binary file not shown.
61
.github/ISSUE_TEMPLATE.md
vendored
61
.github/ISSUE_TEMPLATE.md
vendored
@ -1,59 +1,10 @@
|
||||
<!--
|
||||
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
||||
|
||||
ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
|
||||
-->
|
||||
Please help us process issues more efficiently by filing an
|
||||
issue using one of the following templates:
|
||||
|
||||
## I'm submitting a...
|
||||
<!-- Check one of the following options with "x" -->
|
||||
<pre><code>
|
||||
[ ] Regression (a behavior that used to work and stopped working in a new release)
|
||||
[ ] Bug report <!-- Please search GitHub for a similar issue or PR before submitting -->
|
||||
[ ] Performance issue
|
||||
[ ] Feature request
|
||||
[ ] Documentation issue or request
|
||||
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
|
||||
[ ] Other... Please describe:
|
||||
</code></pre>
|
||||
https://github.com/angular/angular/issues/new/choose
|
||||
|
||||
## Current behavior
|
||||
<!-- Describe how the issue manifests. -->
|
||||
Thank you!
|
||||
|
||||
|
||||
## Expected behavior
|
||||
<!-- Describe what the desired behavior would be. -->
|
||||
|
||||
|
||||
## Minimal reproduction of the problem with instructions
|
||||
<!--
|
||||
For bug reports please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via
|
||||
https://stackblitz.com or similar (you can use this template as a starting point: https://stackblitz.com/fork/angular-gitter).
|
||||
-->
|
||||
|
||||
## What is the motivation / use case for changing the behavior?
|
||||
<!-- Describe the motivation or the concrete use case. -->
|
||||
|
||||
|
||||
## Environment
|
||||
|
||||
<pre><code>
|
||||
Angular version: X.Y.Z
|
||||
<!-- Check whether this is still an issue in the most recent Angular version -->
|
||||
|
||||
Browser:
|
||||
- [ ] Chrome (desktop) version XX
|
||||
- [ ] Chrome (Android) version XX
|
||||
- [ ] Chrome (iOS) version XX
|
||||
- [ ] Firefox version XX
|
||||
- [ ] Safari (desktop) version XX
|
||||
- [ ] Safari (iOS) version XX
|
||||
- [ ] IE version XX
|
||||
- [ ] Edge version XX
|
||||
|
||||
For Tooling issues:
|
||||
- Node version: XX <!-- run `node --version` -->
|
||||
- Platform: <!-- Mac, Linux, Windows -->
|
||||
|
||||
Others:
|
||||
<!-- Anything else relevant? Operating system version, IDE, package manager, HTTP server, ... -->
|
||||
</code></pre>
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
||||
|
63
.github/ISSUE_TEMPLATE/1-bug-report.md
vendored
Normal file
63
.github/ISSUE_TEMPLATE/1-bug-report.md
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
---
|
||||
name: "\U0001F41EBug report"
|
||||
about: Report a bug in the Angular Framework
|
||||
---
|
||||
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅
|
||||
|
||||
Oh hi there! 😄
|
||||
|
||||
To expedite issue processing please search open and closed issues before submitting a new one.
|
||||
Existing issues often contain information about workarounds, resolution, or progress updates.
|
||||
|
||||
🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅-->
|
||||
|
||||
|
||||
# 🐞 bug report
|
||||
|
||||
### Affected Package
|
||||
<!-- Can you pin-point one or more @angular/* packages as the source of the bug? -->
|
||||
<!-- ✍️edit: --> The issue is caused by package @angular/....
|
||||
|
||||
|
||||
### Is this a regression?
|
||||
|
||||
<!-- Did this behavior use to work in the previous version? -->
|
||||
<!-- ✍️--> Yes, the previous version in which this bug was not present was: ....
|
||||
|
||||
|
||||
### Description
|
||||
|
||||
<!-- ✍️--> A clear and concise description of the problem...
|
||||
|
||||
|
||||
## 🔬 Minimal Reproduction
|
||||
<!--
|
||||
Please create and share minimal reproduction of the issue starting with this template: https://stackblitz.com/fork/angular-issue-repro2
|
||||
-->
|
||||
<!-- ✍️--> https://stackblitz.com/...
|
||||
|
||||
<!--
|
||||
If StackBlitz is not suitable for reproduction of your issue, please create a minimal GitHub repository with the reproduction of the issue. Share the link to the repo below along with step-by-step instructions to reproduce the problem, as well as expected and actual behavior.
|
||||
-->
|
||||
|
||||
## 🔥 Exception or Error
|
||||
<pre><code>
|
||||
<!-- If the issue is accompanied by an exception or an error, please share it below: -->
|
||||
<!-- ✍️-->
|
||||
|
||||
</code></pre>
|
||||
|
||||
|
||||
## 🌍 Your Environment
|
||||
|
||||
**Angular Version:**
|
||||
<pre><code>
|
||||
<!-- run `ng version` and paste output below -->
|
||||
<!-- ✍️-->
|
||||
|
||||
</code></pre>
|
||||
|
||||
**Anything else relevant?**
|
||||
<!-- ✍️Is this a browser specific issue? If so, please specify the browser and version. -->
|
||||
|
||||
<!-- ✍️Do any of these matter: operating system, IDE, package manager, HTTP server, ...? If so, please mention it below. -->
|
32
.github/ISSUE_TEMPLATE/2-feature-request.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/2-feature-request.md
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
---
|
||||
name: "\U0001F680Feature request"
|
||||
about: Suggest a feature for Angular Framework
|
||||
|
||||
---
|
||||
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅
|
||||
|
||||
Oh hi there! 😄
|
||||
|
||||
To expedite issue processing please search open and closed issues before submitting a new one.
|
||||
Existing issues often contain information about workarounds, resolution, or progress updates.
|
||||
|
||||
🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅-->
|
||||
|
||||
|
||||
# 🚀 feature request
|
||||
|
||||
### Releavant Package
|
||||
<!-- Can you pin-point one or more @angular/* packages the are relevant for this feature request? -->
|
||||
<!-- ✍️edit: --> This feature request is for @angular/....
|
||||
|
||||
|
||||
### Description
|
||||
<!-- ✍️--> A clear and concise description of the problem or missing capability...
|
||||
|
||||
|
||||
### Describe the solution you'd like
|
||||
<!-- ✍️--> If you have a solution in mind, please describe it.
|
||||
|
||||
|
||||
### Describe alternatives you've considered
|
||||
<!-- ✍️--> Have you considered any alternative solutions or workarounds?
|
55
.github/ISSUE_TEMPLATE/3-docs-bug.md
vendored
Normal file
55
.github/ISSUE_TEMPLATE/3-docs-bug.md
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
---
|
||||
name: "📚 Docs or angular.io issue report"
|
||||
about: Report an issue in Angular's documentation or angular.io application
|
||||
|
||||
---
|
||||
<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅
|
||||
|
||||
Oh hi there! 😄
|
||||
|
||||
To expedite issue processing please search open and closed issues before submitting a new one.
|
||||
Existing issues often contain information about workarounds, resolution, or progress updates.
|
||||
|
||||
🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅-->
|
||||
|
||||
# 📚 Docs or angular.io bug report
|
||||
|
||||
### Description
|
||||
|
||||
<!-- ✍️edit:--> A clear and concise description of the problem...
|
||||
|
||||
|
||||
## 🔬 Minimal Reproduction
|
||||
|
||||
### What's the affected URL?**
|
||||
<!-- ✍️edit:--> https://angular.io/...
|
||||
|
||||
### Reproduction Steps**
|
||||
<!-- If applicable please list the steps to take to reproduce the issue -->
|
||||
<!-- ✍️edit:-->
|
||||
|
||||
### Expected vs Actual Behavior**
|
||||
<!-- If applicable please describe the difference between the expected and actual behavior after following the repro steps. -->
|
||||
<!-- ✍️edit:-->
|
||||
|
||||
|
||||
## 📷Screenshot
|
||||
<!-- Often a screenshot can help to capture the issue better than a long description. -->
|
||||
<!-- ✍️upload a screenshot:-->
|
||||
|
||||
|
||||
## 🔥 Exception or Error
|
||||
<pre><code>
|
||||
<!-- If the issue is accompanied by an exception or an error, please share it below: -->
|
||||
<!-- ✍️-->
|
||||
|
||||
</code></pre>
|
||||
|
||||
|
||||
## 🌍 Your Environment
|
||||
|
||||
### Browser info
|
||||
<!-- ✍️Is this a browser specific issue? If so, please specify the device, browser, and version. -->
|
||||
|
||||
### Anything else relevant?
|
||||
<!-- ✍️Please provide additional info if necessary. -->
|
11
.github/ISSUE_TEMPLATE/4-security-issue-disclosure.md
vendored
Normal file
11
.github/ISSUE_TEMPLATE/4-security-issue-disclosure.md
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
---
|
||||
name: ⚠️ Security issue disclosure
|
||||
about: Report a security issue in Angular Framework, Material, or CLI
|
||||
|
||||
---
|
||||
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
||||
|
||||
Please read https://angular.io/guide/security#report-issues on how to disclose security related issues.
|
||||
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
16
.github/ISSUE_TEMPLATE/5-support-request.md
vendored
Normal file
16
.github/ISSUE_TEMPLATE/5-support-request.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
name: "❓Support request"
|
||||
about: Questions and requests for support
|
||||
|
||||
---
|
||||
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
||||
|
||||
Please do not file questions or support requests on the GitHub issues tracker.
|
||||
|
||||
You can get your questions answered using other communication channels. Please see:
|
||||
https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
|
||||
|
||||
Thank you!
|
||||
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
13
.github/ISSUE_TEMPLATE/6-angular-cli.md
vendored
Normal file
13
.github/ISSUE_TEMPLATE/6-angular-cli.md
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
name: "\U0001F6E0️Angular CLI"
|
||||
about: Issues and feature requests for Angular CLI
|
||||
|
||||
---
|
||||
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
||||
|
||||
Please file any Angular CLI issues at: https://github.com/angular/angular-cli/issues/new
|
||||
|
||||
For the time being, we keep Angular CLI issues in a separate repository.
|
||||
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
13
.github/ISSUE_TEMPLATE/7-angular-material.md
vendored
Normal file
13
.github/ISSUE_TEMPLATE/7-angular-material.md
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
name: "\U0001F48EAngular Material"
|
||||
about: Issues and feature requests for Angular Material
|
||||
|
||||
---
|
||||
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
||||
|
||||
Please file any Angular Material issues at: https://github.com/angular/material2/issues/new
|
||||
|
||||
For the time being, we keep Angular Material issues in a separate repository.
|
||||
|
||||
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
|
21
.github/angular-robot.yml
vendored
21
.github/angular-robot.yml
vendored
@ -39,6 +39,7 @@ merge:
|
||||
- "packages/**"
|
||||
# list of patterns to ignore for the files changed by the PR
|
||||
exclude:
|
||||
- "packages/bazel/*.bzl"
|
||||
- "packages/language-service/**"
|
||||
- "**/.gitignore"
|
||||
- "**/.gitkeep"
|
||||
@ -124,3 +125,23 @@ triage:
|
||||
-
|
||||
- "type: RFC / Discussion / question"
|
||||
- "comp: *"
|
||||
|
||||
# options for the triage PR plugin
|
||||
triagePR:
|
||||
# set to true to disable
|
||||
disabled: false
|
||||
# number of the milestone to apply when the PR has not been triaged yet
|
||||
needsTriageMilestone: 83,
|
||||
# number of the milestone to apply when the PR is triaged
|
||||
defaultMilestone: 82,
|
||||
# arrays of labels that determine if a PR has been triaged by the caretaker
|
||||
l1TriageLabels:
|
||||
-
|
||||
- "comp: *"
|
||||
# arrays of labels that determine if a PR has been fully triaged
|
||||
l2TriageLabels:
|
||||
-
|
||||
- "type: *"
|
||||
- "effort*"
|
||||
- "risk*"
|
||||
- "comp: *"
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,7 +14,6 @@ pubspec.lock
|
||||
.settings/
|
||||
*.swo
|
||||
modules/.settings
|
||||
.bazelrc
|
||||
.vscode
|
||||
modules/.vscode
|
||||
|
||||
|
@ -87,10 +87,10 @@ groups:
|
||||
files:
|
||||
include:
|
||||
- "WORKSPACE"
|
||||
- ".bazel*"
|
||||
- "*.bazel"
|
||||
- "*.bzl"
|
||||
- "packages/bazel/*"
|
||||
- "tools/bazel.rc"
|
||||
- "/docs/BAZEL.md"
|
||||
users:
|
||||
- alexeagle #primary
|
||||
@ -108,9 +108,9 @@ groups:
|
||||
- "*.lock"
|
||||
- "tools/*"
|
||||
exclude:
|
||||
- "tools/bazel.rc"
|
||||
- "tools/public_api_guard/*"
|
||||
- "aio/*"
|
||||
- "packages/core/test/bundling/*"
|
||||
- "tools/public_api_guard/*"
|
||||
users:
|
||||
- IgorMinar #primary
|
||||
- alexeagle
|
||||
@ -277,6 +277,9 @@ groups:
|
||||
- "aio/content/guide/forms.md"
|
||||
- "aio/content/examples/forms/*"
|
||||
- "aio/content/images/guide/forms/*"
|
||||
- "aio/content/guide/forms-overview.md"
|
||||
- "aio/content/examples/forms-overview/*"
|
||||
- "aio/content/images/guide/forms-overview/*"
|
||||
- "aio/content/guide/form-validation.md"
|
||||
- "aio/content/examples/form-validation/*"
|
||||
- "aio/content/images/guide/form-validation/*"
|
||||
|
16
.travis.yml
16
.travis.yml
@ -30,14 +30,6 @@ env:
|
||||
# GITHUB_TOKEN_ANGULAR=<github token, a personal access token of the angular-builds account, account access in valentine>
|
||||
# This is needed for the e2e Travis matrix task to publish packages to github for continuous packages delivery.
|
||||
- secure: "aCdHveZuY8AT4Jr1JoJB4LxZsnGWRe/KseZh1YXYe5UtufFCtTVHvUcLn0j2aLBF0KpdyS+hWf0i4np9jthKu2xPKriefoPgCMpisYeC0MFkwbmv+XlgkUbgkgVZMGiVyX7DCYXVahxIoOUjVMEDCbNiHTIrfEuyq24U3ok2tHc="
|
||||
# FIREBASE_TOKEN
|
||||
# This is needed for publishing builds to the "aio-staging" and "angular-io" firebase projects.
|
||||
# This token was generated using the aio-deploy@angular.io account using `firebase login:ci` and password from valentine
|
||||
- secure: "L5CyQmpwWtoR4Qi4xlWQh/cL1M6ZeJL4W4QAr4HdKFMgYt9h+Whqkymyh2NxwmCbPvWa7yUd+OiLQUDCY7L2VIg16hTwoe2CgYDyQA0BEwLzxtRrJXl93TfwMlrUx5JSIzAccD6D4sjtz8kSFMomK2Nls33xOXOukwyhVMjd0Cg="
|
||||
# ANGULAR_PAYLOAD_FIREBASE_TOKEN
|
||||
# This is for payload size data to "angular-payload-size" firebase project
|
||||
# This token was generated using the payload@angular.io account using `firebase login:ci` and password from valentine
|
||||
- secure: "SxotP/ymNy6uWAVbfwM9BlwETPEBpkRvU/F7fCtQDDic99WfQHzzUSQqHTk8eKk3GrGAOSL09vT0WfStQYEIGEoS5UHWNgOnelxhw+d5EnaoB8vQ0dKQBTK092hQg4feFprr+B/tCasyMV6mVwpUzZMbIJNn/Rx7H5g1bp+Gkfg="
|
||||
matrix:
|
||||
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
|
||||
- CI_MODE=e2e
|
||||
@ -47,16 +39,10 @@ env:
|
||||
# - CI_MODE=browserstack_required
|
||||
- CI_MODE=saucelabs_optional
|
||||
- CI_MODE=browserstack_optional
|
||||
- CI_MODE=aio_tools_test
|
||||
- CI_MODE=aio
|
||||
- CI_MODE=aio_local
|
||||
- CI_MODE=aio_e2e AIO_SHARD=0
|
||||
- CI_MODE=aio_e2e AIO_SHARD=1
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: "CI_MODE=aio_local"
|
||||
- env: "CI_MODE=saucelabs_optional"
|
||||
- env: "CI_MODE=browserstack_optional"
|
||||
|
||||
@ -70,8 +56,6 @@ install:
|
||||
script:
|
||||
- ./scripts/ci/build.sh
|
||||
- ./scripts/ci/test.sh
|
||||
# deploy is part of 'script' and not 'after_success' so that we fail the build if the deployment fails
|
||||
- ./scripts/ci/deploy.sh
|
||||
- ./scripts/ci/angular.sh
|
||||
# all the scripts under this line will not quickly abort in case ${TRAVIS_TEST_RESULT} is 1 (job failure)
|
||||
- ./scripts/ci/cleanup.sh
|
||||
|
50
BUILD.bazel
50
BUILD.bazel
@ -8,26 +8,14 @@ exports_files([
|
||||
"protractor-perf.conf.js",
|
||||
])
|
||||
|
||||
# Developers should always run `bazel run :install`
|
||||
# This ensures that package.json in subdirectories get installed as well.
|
||||
alias(
|
||||
name = "install",
|
||||
actual = "@nodejs//:yarn",
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "node_modules",
|
||||
actual = "@angular_deps//:node_modules",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "web_test_bootstrap_scripts",
|
||||
# do not sort
|
||||
srcs = [
|
||||
"@angular_deps//:node_modules/reflect-metadata/Reflect.js",
|
||||
"@angular_deps//:node_modules/zone.js/dist/zone.js",
|
||||
"@angular_deps//:node_modules/zone.js/dist/zone-testing.js",
|
||||
"@angular_deps//:node_modules/zone.js/dist/task-tracking.js",
|
||||
"@ngdeps//node_modules/reflect-metadata:Reflect.js",
|
||||
"@ngdeps//node_modules/zone.js:dist/zone.js",
|
||||
"@ngdeps//node_modules/zone.js:dist/zone-testing.js",
|
||||
"@ngdeps//node_modules/zone.js:dist/task-tracking.js",
|
||||
"//:test-events.js",
|
||||
],
|
||||
)
|
||||
@ -35,11 +23,29 @@ filegroup(
|
||||
filegroup(
|
||||
name = "angularjs_scripts",
|
||||
srcs = [
|
||||
"@angular_deps//:node_modules/angular-1.5/angular.js",
|
||||
"@angular_deps//:node_modules/angular-1.6/angular.js",
|
||||
"@angular_deps//:node_modules/angular-mocks-1.5/angular-mocks.js",
|
||||
"@angular_deps//:node_modules/angular-mocks-1.6/angular-mocks.js",
|
||||
"@angular_deps//:node_modules/angular-mocks/angular-mocks.js",
|
||||
"@angular_deps//:node_modules/angular/angular.js",
|
||||
"@ngdeps//node_modules/angular:angular.js",
|
||||
"@ngdeps//node_modules/angular-1.5:angular.js",
|
||||
"@ngdeps//node_modules/angular-1.6:angular.js",
|
||||
"@ngdeps//node_modules/angular-mocks:angular-mocks.js",
|
||||
"@ngdeps//node_modules/angular-mocks-1.5:angular-mocks.js",
|
||||
"@ngdeps//node_modules/angular-mocks-1.6:angular-mocks.js",
|
||||
],
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
|
||||
|
||||
# A nodejs_binary for @angular/bazel/ngc-wrapped to use by default in
|
||||
# ng_module that depends on @npm//@angular/bazel instead of the
|
||||
# output of the //packages/bazel/src/ngc-wrapped ts_library rule. This
|
||||
# default is for downstream users that depend on the @angular/bazel npm
|
||||
# package. The generated @npm//@angular/bazel/ngc-wrapped target
|
||||
# does not work because it does not have the node `--expose-gc` flag
|
||||
# set which is required to support the call to `global.gc()`.
|
||||
nodejs_binary(
|
||||
name = "@angular/bazel/ngc-wrapped",
|
||||
configuration_env_vars = ["compile"],
|
||||
data = ["@npm//@angular/bazel"],
|
||||
entry_point = "@angular/bazel/src/ngc-wrapped/index.js",
|
||||
install_source_map_support = False,
|
||||
templated_args = ["--node_options=--expose-gc"],
|
||||
)
|
||||
|
47
CHANGELOG.md
47
CHANGELOG.md
@ -1,12 +1,52 @@
|
||||
<a name="7.0.4"></a>
|
||||
## [7.0.4](https://github.com/angular/angular/compare/7.0.3...7.0.4) (2018-11-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler-cli:** add missing tslib dependency ([#27063](https://github.com/angular/angular/issues/27063)) ([4348c47](https://github.com/angular/angular/commit/4348c47))
|
||||
* **compiler-cli:** only pass canonical genfile paths to compiler host ([#27062](https://github.com/angular/angular/issues/27062)) ([188e9ce](https://github.com/angular/angular/commit/188e9ce))
|
||||
* **router:** add `relativeLinkResolution` to `recognize` operator ([#26990](https://github.com/angular/angular/issues/26990)) ([d304427](https://github.com/angular/angular/commit/d304427)), closes [#26983](https://github.com/angular/angular/issues/26983)
|
||||
|
||||
|
||||
|
||||
<a name="7.0.3"></a>
|
||||
## [7.0.3](https://github.com/angular/angular/compare/7.0.2...7.0.3) (2018-11-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bazel:** unknown replay compiler error in windows ([#26711](https://github.com/angular/angular/issues/26711)) ([4d532df](https://github.com/angular/angular/commit/4d532df))
|
||||
* **router:** remove type bludgeoning of context and outlet when running CanDeactivate ([#26496](https://github.com/angular/angular/issues/26496)) ([dc05385](https://github.com/angular/angular/commit/dc05385)), closes [#18253](https://github.com/angular/angular/issues/18253)
|
||||
* **upgrade:** make typings compatible with older AngularJS typings ([#26880](https://github.com/angular/angular/issues/26880)) ([315d95c](https://github.com/angular/angular/commit/315d95c)), closes [#26420](https://github.com/angular/angular/issues/26420)
|
||||
|
||||
|
||||
|
||||
<a name="7.0.2"></a>
|
||||
## [7.0.2](https://github.com/angular/angular/compare/7.0.1...7.0.2) (2018-10-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler:** generate relative paths only in summary file errors ([#26759](https://github.com/angular/angular/issues/26759)) ([c01f340](https://github.com/angular/angular/commit/c01f340))
|
||||
* **core:** Remove static dependency from [@angular](https://github.com/angular)/core to [@angular](https://github.com/angular)/compiler ([#26734](https://github.com/angular/angular/issues/26734)) ([#26879](https://github.com/angular/angular/issues/26879)) ([257ac83](https://github.com/angular/angular/commit/257ac83))
|
||||
* **core:** support computed base class in metadata inheritance ([#24014](https://github.com/angular/angular/issues/24014)) ([b3c6409](https://github.com/angular/angular/commit/b3c6409))
|
||||
|
||||
|
||||
|
||||
<a name="7.0.1"></a>
|
||||
## [7.0.1](https://github.com/angular/angular/compare/7.0.0...7.0.1) (2018-10-24)
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="7.0.0"></a>
|
||||
# [7.0.0](https://github.com/angular/angular/compare/7.0.0-rc.1...7.0.0) (2018-10-18)
|
||||
|
||||
|
||||
### Release Highlights & Update instructions
|
||||
|
||||
Angular v7 is .
|
||||
|
||||
To learn about the release highlights and our new CLI-powered update workflow for your projects please check out the [v7 release announcement](https://blog.angular.io/TODO).
|
||||
To learn about the release highlights and our new CLI-powered update workflow for your projects please check out the [v7 release announcement](https://blog.angular.io/version-7-of-angular-cli-prompts-virtual-scroll-drag-and-drop-and-more-c594e22e7b8c).
|
||||
|
||||
|
||||
### Dependency updates
|
||||
@ -75,7 +115,6 @@ To learn about the release highlights and our new CLI-powered update workflow fo
|
||||
### Bug Fixes
|
||||
|
||||
* **platform-browser:** fix [#22155](https://github.com/angular/angular/issues/22155), destroy hammer manager when `HammerInstance.off()` is run ([#22156](https://github.com/angular/angular/issues/22156)) ([3b4d9dc](https://github.com/angular/angular/commit/3b4d9dc))
|
||||
* **upgrade:** properly destroy upgraded component elements and descendants ([#26209](https://github.com/angular/angular/issues/26209)) ([623adbb](https://github.com/angular/angular/commit/623adbb)), closes [#26208](https://github.com/angular/angular/issues/26208)
|
||||
|
||||
|
||||
|
||||
|
@ -13,12 +13,10 @@ Angular is a development platform for building mobile and desktop web applicatio
|
||||
|
||||
[Get started in 5 minutes][quickstart].
|
||||
|
||||
|
||||
## Changelog
|
||||
|
||||
[Learn about the latest improvements][changelog].
|
||||
|
||||
|
||||
## Want to help?
|
||||
|
||||
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
|
||||
|
121
WORKSPACE
121
WORKSPACE
@ -1,91 +1,34 @@
|
||||
workspace(name = "angular")
|
||||
|
||||
#
|
||||
# Download Bazel toolchain dependencies as needed by build actions
|
||||
#
|
||||
http_archive(
|
||||
name = "build_bazel_rules_typescript",
|
||||
sha256 = "1626ee2cc9770af6950bfc77dffa027f9aedf330fe2ea2ee7e504428927bd95d",
|
||||
strip_prefix = "rules_typescript-0.17.0",
|
||||
url = "https://github.com/bazelbuild/rules_typescript/archive/0.17.0.zip",
|
||||
load(
|
||||
"//packages/bazel:package.bzl",
|
||||
"rules_angular_dependencies",
|
||||
"rules_angular_dev_dependencies",
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_typescript//:package.bzl", "rules_typescript_dependencies")
|
||||
# Uncomment for local bazel rules development
|
||||
#local_repository(
|
||||
# name = "build_bazel_rules_nodejs",
|
||||
# path = "../rules_nodejs",
|
||||
#)
|
||||
#local_repository(
|
||||
# name = "build_bazel_rules_typescript",
|
||||
# path = "../rules_typescript",
|
||||
#)
|
||||
|
||||
rules_typescript_dependencies()
|
||||
|
||||
http_archive(
|
||||
name = "bazel_toolchains",
|
||||
sha256 = "c3b08805602cd1d2b67ebe96407c1e8c6ed3d4ce55236ae2efe2f1948f38168d",
|
||||
strip_prefix = "bazel-toolchains-5124557861ebf4c0b67f98180bff1f8551e0b421",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/5124557861ebf4c0b67f98180bff1f8551e0b421.tar.gz",
|
||||
"https://github.com/bazelbuild/bazel-toolchains/archive/5124557861ebf4c0b67f98180bff1f8551e0b421.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "io_bazel_rules_sass",
|
||||
sha256 = "dbe9fb97d5a7833b2a733eebc78c9c1e3880f676ac8af16e58ccf2139cbcad03",
|
||||
strip_prefix = "rules_sass-1.11.0",
|
||||
url = "https://github.com/bazelbuild/rules_sass/archive/1.11.0.zip",
|
||||
)
|
||||
|
||||
# This commit matches the version of buildifier in angular/ngcontainer
|
||||
# If you change this, also check if it matches the version in the angular/ngcontainer
|
||||
# version in /.circleci/config.yml
|
||||
BAZEL_BUILDTOOLS_VERSION = "49a6c199e3fbf5d94534b2771868677d3f9c6de9"
|
||||
|
||||
http_archive(
|
||||
name = "com_github_bazelbuild_buildtools",
|
||||
sha256 = "edf39af5fc257521e4af4c40829fffe8fba6d0ebff9f4dd69a6f8f1223ae047b",
|
||||
strip_prefix = "buildtools-%s" % BAZEL_BUILDTOOLS_VERSION,
|
||||
url = "https://github.com/bazelbuild/buildtools/archive/%s.zip" % BAZEL_BUILDTOOLS_VERSION,
|
||||
)
|
||||
|
||||
# Fetching the Bazel source code allows us to compile the Skylark linter
|
||||
http_archive(
|
||||
name = "io_bazel",
|
||||
sha256 = "ace8cced3b21e64a8fdad68508e9b0644201ec848ad583651719841d567fc66d",
|
||||
strip_prefix = "bazel-0.17.1",
|
||||
url = "https://github.com/bazelbuild/bazel/archive/0.17.1.zip",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "io_bazel_skydoc",
|
||||
sha256 = "7bfb5545f59792a2745f2523b9eef363f9c3e7274791c030885e7069f8116016",
|
||||
strip_prefix = "skydoc-fe2e9f888d28e567fef62ec9d4a93c425526d701",
|
||||
# TODO: switch to upstream when https://github.com/bazelbuild/skydoc/pull/103 is merged
|
||||
url = "https://github.com/alexeagle/skydoc/archive/fe2e9f888d28e567fef62ec9d4a93c425526d701.zip",
|
||||
)
|
||||
|
||||
# We have a source dependency on the Devkit repository, because it's built with
|
||||
# Bazel.
|
||||
# This allows us to edit sources and have the effect appear immediately without
|
||||
# re-packaging or "npm link"ing.
|
||||
# Even better, things like aspects will visit the entire graph including
|
||||
# ts_library rules in the devkit repository.
|
||||
http_archive(
|
||||
name = "angular_cli",
|
||||
sha256 = "8cf320ea58c321e103f39087376feea502f20eaf79c61a4fdb05c7286c8684fd",
|
||||
strip_prefix = "angular-cli-6.1.0-rc.0",
|
||||
url = "https://github.com/angular/angular-cli/archive/v6.1.0-rc.0.zip",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "org_brotli",
|
||||
sha256 = "774b893a0700b0692a76e2e5b7e7610dbbe330ffbe3fe864b4b52ca718061d5a",
|
||||
strip_prefix = "brotli-1.0.5",
|
||||
url = "https://github.com/google/brotli/archive/v1.0.5.zip",
|
||||
)
|
||||
# Angular Bazel users will call this function
|
||||
rules_angular_dependencies()
|
||||
# These are the dependencies only for us
|
||||
rules_angular_dev_dependencies()
|
||||
|
||||
#
|
||||
# Point Bazel to WORKSPACEs that live in subdirectories
|
||||
#
|
||||
|
||||
local_repository(
|
||||
http_archive(
|
||||
name = "rxjs",
|
||||
path = "node_modules/rxjs/src",
|
||||
url = "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz",
|
||||
strip_prefix = "package/src",
|
||||
sha256 = "72b0b4e517f43358f554c125e40e39f67688cd2738a8998b4a266981ed32f403",
|
||||
)
|
||||
|
||||
# Point to the integration test workspace just so that Bazel doesn't descend into it
|
||||
@ -98,10 +41,9 @@ local_repository(
|
||||
#
|
||||
# Load and install our dependencies downloaded above.
|
||||
#
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install")
|
||||
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories")
|
||||
|
||||
check_bazel_version("0.17.0", """
|
||||
check_bazel_version("0.18.0", """
|
||||
If you are on a Mac and using Homebrew, there is a breaking change to the installation in Bazel 0.16
|
||||
See https://blog.bazel.build/2018/08/22/bazel-homebrew.html
|
||||
|
||||
@ -114,6 +56,12 @@ node_repositories(
|
||||
yarn_version = "1.9.2",
|
||||
)
|
||||
|
||||
yarn_install(
|
||||
name = "npm",
|
||||
package_json = "//tools:npm/package.json",
|
||||
yarn_lock = "//tools:npm/yarn.lock",
|
||||
)
|
||||
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
|
||||
|
||||
go_rules_dependencies()
|
||||
@ -147,14 +95,3 @@ sass_repositories()
|
||||
load("@io_bazel_skydoc//skylark:skylark.bzl", "skydoc_repositories")
|
||||
|
||||
skydoc_repositories()
|
||||
|
||||
##################################
|
||||
# Prevent Bazel from trying to build rxjs under angular devkit
|
||||
local_repository(
|
||||
name = "rxjs_ignore_nested_1",
|
||||
path = "node_modules/@angular-devkit/core/node_modules/rxjs/src",
|
||||
)
|
||||
local_repository(
|
||||
name = "rxjs_ignore_nested_2",
|
||||
path = "node_modules/@angular-devkit/schematics/node_modules/rxjs/src",
|
||||
)
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
TODO (gkalpak): Add docs. Mention:
|
||||
- Testing on CI.
|
||||
Relevant files: `scripts/ci/test-aio.sh`, `aio/aio-builds-setup/scripts/test.sh`
|
||||
Relevant files: `aio/aio-builds-setup/scripts/test.sh`
|
||||
- Deploying from CI.
|
||||
Relevant files: `.circleci/config.yml`, `scripts/ci/deploy.sh`, `aio/scripts/build-artifacts.sh`,
|
||||
`aio/scripts/deploy-to-firebase.sh`
|
||||
|
@ -33,7 +33,8 @@ cd my-first-project
|
||||
ng serve
|
||||
</code-example>
|
||||
|
||||
In your browser, open http://localhost:4200/ to see the new app run.
|
||||
In your browser, open http://localhost:4200/ to see the new app run.
|
||||
When you use the [ng serve](cli/serve) command to build an app and serve it locally, the server automatically rebuilds the app and reloads the page when you change any of the source files.
|
||||
|
||||
## Workspaces and project files
|
||||
|
||||
@ -49,16 +50,15 @@ You can edit the generated files directly, or add to and modify them using CLI c
|
||||
Use the [ng generate](cli/generate) command to add new files for additional components and services, and code for new pipes, directives, and so on.
|
||||
Commands such as [add](cli/add) and [generate](cli/generate), which create or operate on apps and libraries, must be executed from within a workspace or project folder.
|
||||
|
||||
When you use the [ng serve](cli/serve) command to build an app and serve it locally, the server automatically rebuilds the app and reloads the page when you change any of the source files.
|
||||
|
||||
* See more about the [Workspace file structure](guide/file-structure).
|
||||
|
||||
When you use the [ng serve](cli/serve) command to build an app and serve it locally, the server automatically rebuilds the app and reloads the page when you change any of the source files.
|
||||
### Workspace and project configuration
|
||||
|
||||
A single workspace configuration file, `angular.json`, is created at the top level of the workspace.
|
||||
This is where you can set workspace-wide defaults, and specify configurations to use when the CLI builds a project for different targets.
|
||||
This is where you can set per-project defaults for CLI command options, and specify configurations to use when the CLI builds a project for different targets.
|
||||
|
||||
The [ng config](cli/config) command lets you set and retrieve configuration values from the command line, or you can edit the `angular.json` file directly.
|
||||
The [ng config](cli/config) command lets you set and retrieve configuration values from the command line, or you can edit the `angular.json` file directly.
|
||||
Note that option names in the configuration file must use [camelCase](guide/glossary#case-types), while option names supplied to commands can use either camelCase or dash-case.
|
||||
|
||||
* See the [complete schema](https://github.com/angular/angular-cli/wiki/angular-workspace) for `angular.json`.
|
||||
<!-- * Learn more about *configuration options for Angular(links to new guide or topics TBD)*. -->
|
||||
|
@ -1,6 +1,6 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser } from 'protractor';
|
||||
import { browser, ExpectedConditions as EC } from 'protractor';
|
||||
import { logging } from 'selenium-webdriver';
|
||||
import * as openClose from './open-close.po';
|
||||
import * as statusSlider from './status-slider.po';
|
||||
@ -25,6 +25,8 @@ describe('Animation Tests', () => {
|
||||
});
|
||||
|
||||
describe('Open/Close Component', () => {
|
||||
const closedHeight = '100px';
|
||||
const openHeight = '200px';
|
||||
|
||||
beforeAll(async () => {
|
||||
await openCloseHref.click();
|
||||
@ -32,37 +34,37 @@ describe('Animation Tests', () => {
|
||||
});
|
||||
|
||||
it('should be open', async () => {
|
||||
let text = await openClose.getComponentText();
|
||||
const toggleButton = openClose.getToggleButton();
|
||||
const container = openClose.getComponentContainer();
|
||||
let text = await container.getText();
|
||||
|
||||
if (text.includes('Closed')) {
|
||||
await toggleButton.click();
|
||||
sleepFor();
|
||||
await browser.wait(async () => await container.getCssValue('height') === openHeight, 2000);
|
||||
}
|
||||
|
||||
text = await openClose.getComponentText();
|
||||
text = await container.getText();
|
||||
const containerHeight = await container.getCssValue('height');
|
||||
|
||||
expect(text).toContain('The box is now Open!');
|
||||
expect(containerHeight).toBe('200px');
|
||||
expect(containerHeight).toBe(openHeight);
|
||||
});
|
||||
|
||||
it('should be closed', async () => {
|
||||
let text = await openClose.getComponentText();
|
||||
const toggleButton = openClose.getToggleButton();
|
||||
const container = openClose.getComponentContainer();
|
||||
let text = await container.getText();
|
||||
|
||||
if (text.includes('Open')) {
|
||||
await toggleButton.click();
|
||||
sleepFor();
|
||||
await browser.wait(async () => await container.getCssValue('height') === closedHeight, 2000);
|
||||
}
|
||||
|
||||
text = await openClose.getComponentText();
|
||||
text = await container.getText();
|
||||
const containerHeight = await container.getCssValue('height');
|
||||
|
||||
expect(text).toContain('The box is now Closed!');
|
||||
expect(containerHeight).toBe('100px');
|
||||
expect(containerHeight).toBe(closedHeight);
|
||||
});
|
||||
|
||||
it('should log animation events', async () => {
|
||||
@ -72,8 +74,7 @@ describe('Animation Tests', () => {
|
||||
await toggleButton.click();
|
||||
|
||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||
|
||||
const animationMessages = logs.filter(({ message }) => message.indexOf('Animation') !== -1 ? true : false);
|
||||
const animationMessages = logs.filter(({ message }) => message.includes('Animation'));
|
||||
|
||||
expect(animationMessages.length).toBeGreaterThan(0);
|
||||
});
|
||||
@ -89,16 +90,16 @@ describe('Animation Tests', () => {
|
||||
});
|
||||
|
||||
it('should be inactive with an orange background', async () => {
|
||||
let text = await statusSlider.getComponentText();
|
||||
const toggleButton = statusSlider.getToggleButton();
|
||||
const container = statusSlider.getComponentContainer();
|
||||
let text = await container.getText();
|
||||
|
||||
if (text === 'Active') {
|
||||
await toggleButton.click();
|
||||
sleepFor(2000);
|
||||
await browser.wait(async () => await container.getCssValue('backgroundColor') === inactiveColor, 2000);
|
||||
}
|
||||
|
||||
text = await statusSlider.getComponentText();
|
||||
text = await container.getText();
|
||||
const bgColor = await container.getCssValue('backgroundColor');
|
||||
|
||||
expect(text).toBe('Inactive');
|
||||
@ -106,16 +107,16 @@ describe('Animation Tests', () => {
|
||||
});
|
||||
|
||||
it('should be active with a blue background', async () => {
|
||||
let text = await statusSlider.getComponentText();
|
||||
const toggleButton = statusSlider.getToggleButton();
|
||||
const container = statusSlider.getComponentContainer();
|
||||
let text = await container.getText();
|
||||
|
||||
if (text === 'Inactive') {
|
||||
await toggleButton.click();
|
||||
sleepFor(2000);
|
||||
await browser.wait(async () => await container.getCssValue('backgroundColor') === activeColor, 2000);
|
||||
}
|
||||
|
||||
text = await statusSlider.getComponentText();
|
||||
text = await container.getText();
|
||||
const bgColor = await container.getCssValue('backgroundColor');
|
||||
|
||||
expect(text).toBe('Active');
|
||||
@ -163,10 +164,7 @@ describe('Animation Tests', () => {
|
||||
const hero = heroesList.get(0);
|
||||
|
||||
await hero.click();
|
||||
await sleepFor(100);
|
||||
const newTotal = await heroesList.count();
|
||||
|
||||
expect(newTotal).toBeLessThan(total);
|
||||
await browser.wait(async () => await heroesList.count() < total, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
@ -190,10 +188,7 @@ describe('Animation Tests', () => {
|
||||
const hero = heroesList.get(0);
|
||||
|
||||
await hero.click();
|
||||
await sleepFor(250);
|
||||
const newTotal = await heroesList.count();
|
||||
|
||||
expect(newTotal).toBeLessThan(total);
|
||||
await browser.wait(async () => await heroesList.count() < total, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
@ -213,14 +208,14 @@ describe('Animation Tests', () => {
|
||||
it('should filter down the list when a search is performed', async () => {
|
||||
const heroesList = filterStagger.getHeroesList();
|
||||
const total = await heroesList.count();
|
||||
|
||||
const formInput = filterStagger.getFormInput();
|
||||
|
||||
await formInput.sendKeys('Mag');
|
||||
await sleepFor(500);
|
||||
const newTotal = await heroesList.count();
|
||||
|
||||
await browser.wait(async () => await heroesList.count() === 2, 2000);
|
||||
|
||||
const newTotal = await heroesList.count();
|
||||
expect(newTotal).toBeLessThan(total);
|
||||
expect(newTotal).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
@ -248,10 +243,7 @@ describe('Animation Tests', () => {
|
||||
const hero = heroesList.get(0);
|
||||
|
||||
await hero.click();
|
||||
await sleepFor(300);
|
||||
const newTotal = await heroesList.count();
|
||||
|
||||
expect(newTotal).toBeLessThan(total);
|
||||
await browser.wait(async () => await heroesList.count() < total, 2000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -23,11 +23,3 @@ export function getComponentContainer() {
|
||||
const findContainer = () => by.css('div');
|
||||
return locate(getComponent(), findContainer());
|
||||
}
|
||||
|
||||
export async function getComponentText() {
|
||||
const findContainerText = () => by.css('div');
|
||||
const contents = locate(getComponent(), findContainerText());
|
||||
const componentText = await contents.getText();
|
||||
|
||||
return componentText;
|
||||
}
|
||||
|
@ -18,11 +18,3 @@ export function getComponentContainer() {
|
||||
const findContainer = () => by.css('div');
|
||||
return locate(getComponent(), findContainer());
|
||||
}
|
||||
|
||||
export async function getComponentText() {
|
||||
const findContainerText = () => by.css('div');
|
||||
const contents = locate(getComponent(), findContainerText());
|
||||
const componentText = await contents.getText();
|
||||
|
||||
return componentText;
|
||||
}
|
||||
|
@ -1,12 +1,23 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser, by, element } from 'protractor';
|
||||
import { browser, by, element, ElementFinder, ExpectedConditions as EC } from 'protractor';
|
||||
|
||||
/* tslint:disable:quotemark */
|
||||
describe('Elements', () => {
|
||||
const messageInput = element(by.css('input'));
|
||||
const popupButtons = element.all(by.css('button'));
|
||||
|
||||
// Helpers
|
||||
const click = (elem: ElementFinder) => {
|
||||
// Waiting for the element to be clickable, makes the tests less flaky.
|
||||
browser.wait(EC.elementToBeClickable(elem), 5000);
|
||||
elem.click();
|
||||
};
|
||||
const waitForText = (elem: ElementFinder) => {
|
||||
// Waiting for the element to have some text, makes the tests less flaky.
|
||||
browser.wait(async () => /\S/.test(await elem.getText()), 5000);
|
||||
}
|
||||
|
||||
beforeEach(() => browser.get(''));
|
||||
|
||||
describe('popup component', () => {
|
||||
@ -17,7 +28,7 @@ describe('Elements', () => {
|
||||
it('should be displayed on button click', () => {
|
||||
expect(popupComponent.isPresent()).toBe(false);
|
||||
|
||||
popupComponentButton.click();
|
||||
click(popupComponentButton);
|
||||
expect(popupComponent.isPresent()).toBe(true);
|
||||
});
|
||||
|
||||
@ -25,7 +36,9 @@ describe('Elements', () => {
|
||||
messageInput.clear();
|
||||
messageInput.sendKeys('Angular rocks!');
|
||||
|
||||
popupComponentButton.click();
|
||||
click(popupComponentButton);
|
||||
waitForText(popupComponent);
|
||||
|
||||
expect(popupComponent.getText()).toContain('Popup: Angular rocks!');
|
||||
});
|
||||
|
||||
@ -33,7 +46,7 @@ describe('Elements', () => {
|
||||
popupComponentButton.click();
|
||||
expect(popupComponent.isPresent()).toBe(true);
|
||||
|
||||
closeButton.click();
|
||||
click(closeButton);
|
||||
expect(popupComponent.isPresent()).toBe(false);
|
||||
});
|
||||
});
|
||||
@ -46,7 +59,7 @@ describe('Elements', () => {
|
||||
it('should be displayed on button click', () => {
|
||||
expect(popupElement.isPresent()).toBe(false);
|
||||
|
||||
popupElementButton.click();
|
||||
click(popupElementButton);
|
||||
expect(popupElement.isPresent()).toBe(true);
|
||||
});
|
||||
|
||||
@ -54,7 +67,9 @@ describe('Elements', () => {
|
||||
messageInput.clear();
|
||||
messageInput.sendKeys('Angular rocks!');
|
||||
|
||||
popupElementButton.click();
|
||||
click(popupElementButton);
|
||||
waitForText(popupElement);
|
||||
|
||||
expect(popupElement.getText()).toContain('Popup: Angular rocks!');
|
||||
});
|
||||
|
||||
@ -62,7 +77,7 @@ describe('Elements', () => {
|
||||
popupElementButton.click();
|
||||
expect(popupElement.isPresent()).toBe(true);
|
||||
|
||||
closeButton.click();
|
||||
click(closeButton);
|
||||
expect(popupElement.isPresent()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -72,15 +72,15 @@
|
||||
<h2>You submitted the following:</h2>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">Name</div>
|
||||
<div class="col-xs-9 pull-left">{{ model.name }}</div>
|
||||
<div class="col-xs-9">{{ model.name }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">Alter Ego</div>
|
||||
<div class="col-xs-9 pull-left">{{ model.alterEgo }}</div>
|
||||
<div class="col-xs-9">{{ model.alterEgo }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">Power</div>
|
||||
<div class="col-xs-9 pull-left">{{ model.power }}</div>
|
||||
<div class="col-xs-9">{{ model.power }}</div>
|
||||
</div>
|
||||
<br>
|
||||
<button class="btn btn-primary" (click)="submitted=false">Edit</button>
|
||||
|
@ -12,7 +12,7 @@ h2, h3 {
|
||||
body {
|
||||
margin: 2em;
|
||||
}
|
||||
body, input[text], button {
|
||||
body, input[type="text"], button {
|
||||
color: #888;
|
||||
font-family: Cambria, Georgia;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<h4>Hero Search</h4>
|
||||
|
||||
<!-- #docregion input -->
|
||||
<input #searchBox id="search-box" (keyup)="search(searchBox.value)" />
|
||||
<input #searchBox id="search-box" (input)="search(searchBox.value)" />
|
||||
<!-- #enddocregion input -->
|
||||
|
||||
<ul class="search-result">
|
||||
|
@ -40,7 +40,7 @@ export class HeroService {
|
||||
// #enddocregion getHeroes-1
|
||||
.pipe(
|
||||
// #enddocregion getHeroes-2
|
||||
tap(heroes => this.log('fetched heroes')),
|
||||
tap(_ => this.log('fetched heroes')),
|
||||
// #docregion getHeroes-2
|
||||
catchError(this.handleError('getHeroes', []))
|
||||
);
|
||||
|
@ -1,7 +1,11 @@
|
||||
// #docregion , init
|
||||
import { InMemoryDbService } from 'angular-in-memory-web-api';
|
||||
import { Hero } from './hero';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class InMemoryDataService implements InMemoryDbService {
|
||||
createDb() {
|
||||
const heroes = [
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div id="search-component">
|
||||
<h4>Hero Search</h4>
|
||||
|
||||
<input #searchBox id="search-box" (keyup)="search(searchBox.value)" />
|
||||
<input #searchBox id="search-box" (input)="search(searchBox.value)" />
|
||||
|
||||
<ul class="search-result">
|
||||
<li *ngFor="let hero of heroes | async" >
|
||||
|
@ -1,6 +1,6 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser, element, by, ElementFinder } from 'protractor';
|
||||
import { browser, element, by, ElementArrayFinder, ElementFinder } from 'protractor';
|
||||
|
||||
// Angular E2E Testing Guide:
|
||||
// https://docs.angularjs.org/guide/e2e-testing
|
||||
@ -20,6 +20,12 @@ describe('PhoneCat Application', function() {
|
||||
|
||||
describe('View: Phone list', function() {
|
||||
|
||||
// Helpers
|
||||
const waitForCount = (elems: ElementArrayFinder, count: number) => {
|
||||
// Wait for the list to stabilize, which may take a while (e.g. due to animations).
|
||||
browser.wait(() => elems.count().then(c => c === count), 5000);
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
browser.get('index.html#!/phones');
|
||||
});
|
||||
@ -28,13 +34,16 @@ describe('PhoneCat Application', function() {
|
||||
let phoneList = element.all(by.repeater('phone in $ctrl.phones'));
|
||||
let query = element(by.model('$ctrl.query'));
|
||||
|
||||
waitForCount(phoneList, 20);
|
||||
expect(phoneList.count()).toBe(20);
|
||||
|
||||
query.sendKeys('nexus');
|
||||
waitForCount(phoneList, 1);
|
||||
expect(phoneList.count()).toBe(1);
|
||||
|
||||
query.clear();
|
||||
query.sendKeys('motorola');
|
||||
waitForCount(phoneList, 8);
|
||||
expect(phoneList.count()).toBe(8);
|
||||
});
|
||||
|
||||
@ -51,6 +60,7 @@ describe('PhoneCat Application', function() {
|
||||
}
|
||||
|
||||
queryField.sendKeys('tablet'); // Let's narrow the dataset to make the assertions shorter
|
||||
waitForCount(phoneNameColumn, 2);
|
||||
|
||||
expect(getNames()).toEqual([
|
||||
'Motorola XOOM\u2122 with Wi-Fi',
|
||||
@ -66,10 +76,16 @@ describe('PhoneCat Application', function() {
|
||||
});
|
||||
|
||||
it('should render phone specific links', function() {
|
||||
let phoneList = element.all(by.repeater('phone in $ctrl.phones'));
|
||||
let query = element(by.model('$ctrl.query'));
|
||||
query.sendKeys('nexus');
|
||||
|
||||
element.all(by.css('.phones li a')).first().click();
|
||||
query.sendKeys('nexus');
|
||||
waitForCount(phoneList, 1);
|
||||
|
||||
let nexusPhone = phoneList.first();
|
||||
let detailLink = nexusPhone.all(by.css('a')).first()
|
||||
|
||||
detailLink.click();
|
||||
expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s');
|
||||
});
|
||||
|
||||
|
@ -48,7 +48,7 @@ Similarly, use the `@Injectable()` decorator to indicate that a component or oth
|
||||
|
||||
* An injector creates dependencies, and maintains a *container* of dependency instances that it reuses if possible.
|
||||
|
||||
* A *provider* is an object that tell an injector how to obtain or create a dependency.
|
||||
* A *provider* is an object that tells an injector how to obtain or create a dependency.
|
||||
|
||||
For any dependency that you need in your app, you must register a provider with the app's injector,
|
||||
so that the injector can use the provider to create new instances.
|
||||
|
@ -268,7 +268,7 @@ Each budget entry is a JSON object with the following properties:
|
||||
The CLI uses [Autoprefixer](https://github.com/postcss/autoprefixer) to ensure compatibility with different browser and browser versions.
|
||||
You may find it necessary to target specific browsers or exclude certain browser versions from your build.
|
||||
|
||||
Internally, Autoprefixer relies on a library called [Browserslist(https://github.com/ai/browserslist)] to figure out which browsers to support with prefixing.
|
||||
Internally, Autoprefixer relies on a library called [Browserslist](https://github.com/browserslist/browserslist) to figure out which browsers to support with prefixing.
|
||||
Browserlist looks for configuration options in a `browserlist` property of the package configuration file, or in a configuration file named `.browserslistrc`.
|
||||
Autoprefixer looks for the Browserlist configuration when it prefixes your CSS.
|
||||
|
||||
@ -287,7 +287,7 @@ Autoprefixer looks for the Browserlist configuration when it prefixes your CSS.
|
||||
last 2 versions
|
||||
```
|
||||
|
||||
See the [browserslist repo](https://github.com/ai/browserslist) for more examples of how to target specific browsers and versions.
|
||||
See the [browserslist repo](https://github.com/browserslist/browserslist) for more examples of how to target specific browsers and versions.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
Backward compatibility
|
||||
|
@ -1,19 +1,19 @@
|
||||
# Deployment
|
||||
|
||||
When you are ready to deploy your Angular application to a remote server, you have various options for
|
||||
deployment.
|
||||
deployment.
|
||||
|
||||
{@a dev-deploy}
|
||||
{@a copy-files}
|
||||
|
||||
## Simplest deployment possible
|
||||
|
||||
For the simplest deployment, build for development and copy the output directory to a web server.
|
||||
For the simplest deployment, create a production build and copy the output directory to a web server.
|
||||
|
||||
1. Start with the development build:
|
||||
1. Start with the production build:
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
ng build
|
||||
ng build --prod
|
||||
</code-example>
|
||||
|
||||
|
||||
@ -22,8 +22,7 @@ For the simplest deployment, build for development and copy the output directory
|
||||
3. Configure the server to redirect requests for missing files to `index.html`.
|
||||
Learn more about server-side redirects [below](#fallback).
|
||||
|
||||
This is _not_ a production deployment. It's not optimized, and it won't be fast for users.
|
||||
It might be good enough for sharing your progress and ideas internally with managers, teammates, and other stakeholders. For the next steps in deployment, see [Optimize for production](#optimize).
|
||||
This is the simplest production-ready deployment of your application.
|
||||
|
||||
{@a deploy-to-github}
|
||||
|
||||
@ -31,7 +30,7 @@ It might be good enough for sharing your progress and ideas internally with mana
|
||||
|
||||
Another simple way to deploy your Angular app is to use [GitHub Pages](https://help.github.com/articles/what-is-github-pages/).
|
||||
|
||||
1. You need to [create a GitHub account](https://github.com/join) if you don't have one, and then [create a repository](https://help.github.com/articles/create-a-repo/) for your project.
|
||||
1. You need to [create a GitHub account](https://github.com/join) if you don't have one, and then [create a repository](https://help.github.com/articles/create-a-repo/) for your project.
|
||||
Make a note of the user name and project name in GitHub.
|
||||
|
||||
1. Build your project using Github project name, with the Angular CLI command [`ng build`](cli/build) and the options shown here:
|
||||
@ -39,9 +38,9 @@ Make a note of the user name and project name in GitHub.
|
||||
ng build --prod --output-path docs --base-href <project_name>
|
||||
</code-example>
|
||||
|
||||
1. When the build is complete, make a copy of `docs/index.html` and name it `docs/404.html`.
|
||||
1. When the build is complete, make a copy of `docs/index.html` and name it `docs/404.html`.
|
||||
|
||||
1. Commit your changes and push.
|
||||
1. Commit your changes and push.
|
||||
|
||||
1. On the GitHub project page, configure it to [publish from the docs folder](https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch).
|
||||
|
||||
@ -97,51 +96,6 @@ There is no single configuration that works for every server.
|
||||
The following sections describe configurations for some of the most popular servers.
|
||||
The list is by no means exhaustive, but should provide you with a good starting point.
|
||||
|
||||
#### Development servers
|
||||
|
||||
During development, the [`ng serve`](cli/serve) CLI command lets you run your app in a local browser.
|
||||
The CLI recompiles the application each time you save a file,
|
||||
and reloads the browser with the newly compiled application.
|
||||
|
||||
The app is hosted in local memory and served on `http://localhost:4200/`, using [webpack-dev-server](https://webpack.js.org/guides/development/#webpack-dev-server).
|
||||
|
||||
{@a serve-from-disk}
|
||||
|
||||
Later in development, you might want a closer approximation of how your app will behave when deployed.
|
||||
You can output your distribution folder (`dist`) to disk, but you need to install a different web server.
|
||||
Try installing [lite-server](https://github.com/johnpapa/lite-server); like `webpack-dev-server`, it can automatically reload your browser when you write new files.
|
||||
|
||||
To get the live-reload experience, you will need to run two terminals.
|
||||
The first runs the build in a watch mode and compiles the application to the `dist` folder.
|
||||
The second runs the web server against the `dist` folder.
|
||||
The combination of these two processes provides the same behavior as `ng serve`.
|
||||
|
||||
1. Start the build in terminal A:
|
||||
<code-example language="none" class="code-shell">
|
||||
ng build --watch
|
||||
</code-example>
|
||||
|
||||
1. Start the web server in terminal B:
|
||||
<code-example language="none" class="code-shell">
|
||||
lite-server --baseDir="dist"
|
||||
</code-example>
|
||||
The default browser opens to the appropriate URL.
|
||||
|
||||
* [Lite-Server](https://github.com/johnpapa/lite-server): the default dev server installed with the
|
||||
[Quickstart repo](https://github.com/angular/quickstart) is pre-configured to fallback to `index.html`.
|
||||
|
||||
* [Webpack-Dev-Server](https://github.com/webpack/webpack-dev-server): setup the
|
||||
`historyApiFallback` entry in the dev server options as follows:
|
||||
|
||||
<code-example>
|
||||
historyApiFallback: {
|
||||
disableDotRule: true,
|
||||
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml']
|
||||
}
|
||||
</code-example>
|
||||
|
||||
#### Production servers
|
||||
|
||||
* [Apache](https://httpd.apache.org/): add a
|
||||
[rewrite rule](http://httpd.apache.org/docs/current/mod/mod_rewrite.html) to the `.htaccess` file as shown
|
||||
(https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/):
|
||||
@ -230,19 +184,9 @@ Read about how to enable CORS for specific servers at
|
||||
|
||||
{@a optimize}
|
||||
|
||||
## Optimize for production
|
||||
## Production optimizations
|
||||
|
||||
Although deploying directly from the development environment works,
|
||||
you can generate an optimized build with additional CLI command line flags,
|
||||
starting with `--prod`.
|
||||
|
||||
### Build with _--prod_
|
||||
|
||||
<code-example language="none" class="code-shell">
|
||||
ng build --prod
|
||||
</code-example>
|
||||
|
||||
The `--prod` _meta-flag_ engages the following optimization features.
|
||||
The `--prod` _meta-flag_ engages the following build optimization features.
|
||||
|
||||
* [Ahead-of-Time (AOT) Compilation](guide/aot-compiler): pre-compiles Angular component templates.
|
||||
* [Production mode](#enable-prod-mode): deploys the production environment which enables _production mode_.
|
||||
@ -251,25 +195,22 @@ The `--prod` _meta-flag_ engages the following optimization features.
|
||||
* Uglification: rewrites code to use short, cryptic variable and function names.
|
||||
* Dead code elimination: removes unreferenced modules and much unused code.
|
||||
|
||||
The remaining [copy deployment steps](#copy-files) are the same as before.
|
||||
|
||||
See [`ng build`](cli/build) for more about CLI build options and what they do.
|
||||
|
||||
|
||||
{@a enable-prod-mode}
|
||||
|
||||
### Enable production mode
|
||||
### Enable runtime production mode
|
||||
|
||||
Angular apps run in development mode by default, as you can see by the following message on the browser
|
||||
console:
|
||||
In addition to build optimizations, Angular also has a runtime production mode. Angular apps run in development mode by default, as you can see by the following message on the browser console:
|
||||
|
||||
<code-example format="nocode">
|
||||
Angular is running in the development mode. Call enableProdMode() to enable the production mode.
|
||||
</code-example>
|
||||
|
||||
Switching to _production mode_ can make it run faster by disabling development specific checks such as the dual change detection cycles.
|
||||
Switching to _production mode_ makes it run faster by disabling development specific checks such as the dual change detection cycles.
|
||||
|
||||
Building for production (or appending the `--environment=prod` flag) enables _production mode_
|
||||
Look at the CLI-generated `main.ts` to see how this works.
|
||||
When you enable production builds via `--prod` command line flag, the runtime production mode is enabled as well.
|
||||
|
||||
{@a lazy-loading}
|
||||
|
||||
@ -293,7 +234,7 @@ If you do that, the module will be loaded immediately.
|
||||
|
||||
The bundling configuration must take lazy loading into consideration.
|
||||
Because lazy-loaded modules aren't imported in JavaScript, bundlers exclude them by default.
|
||||
Bundlers don't know about the router configuration and can't create separate bundles for lazy-loaded modules.
|
||||
Bundlers don't know about the router configuration and can't create separate bundles for lazy-loaded modules.
|
||||
You would have to create these bundles manually.
|
||||
|
||||
The CLI runs the
|
||||
@ -388,7 +329,7 @@ for the missing files. Look at where it _tried_ to find those files and adjust t
|
||||
|
||||
## Building and serving for deployment
|
||||
|
||||
When you are designing and developing applications, you typically use `ng serve` to build your app for fast, local, iterative development.
|
||||
When you are designing and developing applications, you typically use `ng serve` to build your app for fast, local, iterative development.
|
||||
When you are ready to deploy, however, you must use the `ng build` command to build the app and deploy the build artifacts elsewhere.
|
||||
|
||||
Both `ng build` and `ng serve` clear the output folder before they build the project, but only the `ng build` command writes the generated build artifacts to the output folder.
|
||||
@ -401,12 +342,12 @@ To output to a different folder, change the `outputPath` in `angular.json`.
|
||||
</div>
|
||||
|
||||
The `ng serve` command builds, watches, and serves the application from local memory, using a local development server.
|
||||
When you have deployed your app to another server, however, you might still want to serve the app so that you can continue to see changes that you make in it.
|
||||
When you have deployed your app to another server, however, you might still want to serve the app so that you can continue to see changes that you make in it.
|
||||
You can do this by adding the `--watch` option to the `ng build` command.
|
||||
|
||||
```
|
||||
ng build --watch
|
||||
```
|
||||
Like the `ng serve` command, this regenerates output files when source files change.
|
||||
Like the `ng serve` command, this regenerates output files when source files change.
|
||||
|
||||
For complete details of the CLI commands, see the [CLI command reference](cli).
|
||||
|
@ -357,7 +357,7 @@ big chunks of HTML with many data bindings.
|
||||
|
||||
|
||||
Try it out. Because the array has four items, the message should appear.
|
||||
Go back into <code>app.component.ts"</code> and delete or comment out one of the elements from the hero array.
|
||||
Go back into <code>app.component.ts</code> and delete or comment out one of the elements from the hero array.
|
||||
The browser should refresh automatically and the message should disappear.
|
||||
|
||||
|
||||
|
@ -107,7 +107,7 @@ The recently-developed [custom elements](https://developer.mozilla.org/en-US/doc
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Firefox</td>
|
||||
<td> Set the <code>dom.webcomponents.enabled</code> and <code>dom.webcomponents.customelements.enabled</code> preferences to true. Planned to be enabled by default in version 63.</td>
|
||||
<td>Supported natively as of version 63. In older versions: Set the <code>dom.webcomponents.enabled</code> and <code>dom.webcomponents.customelements.enabled</code> preferences to true.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Edge</td>
|
||||
|
@ -98,7 +98,7 @@ When the CLI generated the `CustomerDashboardComponent` for the feature module,
|
||||
</code-example>
|
||||
|
||||
|
||||
To see this HTML in the `AppComponent`, you first have to export the `CustomerDashboardComponent` in the `CustomerDashboardModule`. In `customer-dashboard.module.ts`, just beneath the `declarations` array, add an `exports` array containing `CustomerDashboardModule`:
|
||||
To see this HTML in the `AppComponent`, you first have to export the `CustomerDashboardComponent` in the `CustomerDashboardModule`. In `customer-dashboard.module.ts`, just beneath the `declarations` array, add an `exports` array containing `CustomerDashboardComponent`:
|
||||
|
||||
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="component-exports" header="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false">
|
||||
</code-example>
|
||||
|
@ -20,16 +20,15 @@ The top level of the workspace contains a number of workspace-wide configuration
|
||||
| :--------------------- | :------------------------------------------|
|
||||
| `.editorconfig` | Configuration for code editors. See [EditorConfig](https://editorconfig.org/). |
|
||||
| `.gitignore` | Specifies intentionally untracked files that [Git](https://git-scm.com/) should ignore. |
|
||||
| `angular.json` | CLI configuration for all projects in the workspace, including configuration options for build, serve, and test tools that the CLI uses, such as [Karma](https://karma-runner.github.io/) and [Protractor](http://www.protractortest.org/). |
|
||||
| `angular.json` | CLI configuration defaults for all projects in the workspace, including configuration options for build, serve, and test tools that the CLI uses, such as [TSLint](https://palantir.github.io/tslint/), [Karma](https://karma-runner.github.io/), and [Protractor](http://www.protractortest.org/). For details, see [Angular Workspace Configuration](guide/workspace-config). |
|
||||
| `node_modules` | Provides [npm packages](guide/npm-packages) to the entire workspace. |
|
||||
| `package.json` | Lists package dependencies. See [npm documentation](https://docs.npmjs.com/files/package.json) for the specific format and contents of this file.|
|
||||
| `tsconfig.app.json` | Default [TypeScript](https://www.typescriptlang.org/) configuration for apps in the workspace. |
|
||||
| `tsconfig.spec.json` | Default TypeScript configuration for e2e test apps in the workspace. |
|
||||
| `tslint.json` | Default [TSLint](https://palantir.github.io/tslint/) configuration for apps in the workspace. |
|
||||
| `README.md` | Introductory documentation. |
|
||||
| `package.json` | Configures [npm package dependencies](guide/npm-packages) that are available to all projects in the workspace. See [npm documentation](https://docs.npmjs.com/files/package.json) for the specific format and contents of this file. |
|
||||
| `package-lock.json` | Provides version information for all packages installed into `node_modules` by the npm client. See [npm documentation](https://docs.npmjs.com/files/package-lock.json) for details. If you use the yarn client, this file will be [yarn.lock](https://yarnpkg.com/lang/en/docs/yarn-lock/) instead. |
|
||||
| `tsconfig.json` | Default [TypeScript](https://www.typescriptlang.org/) configuration for apps in the workspace, including TypeScript and Angular template compiler options. See [TypeScript Configuration](guide/typescript-configuration). |
|
||||
| `tslint.json` | Default [TSLint](https://palantir.github.io/tslint/) configuration for apps in the workspace. |
|
||||
| `README.md` | Introductory documentation. |
|
||||
|
||||
All projects within a workspace share this configuration context.
|
||||
All projects within a workspace share a [CLI configuration context](guide/workspace-config).
|
||||
Project-specific [TypeScript](https://www.typescriptlang.org/) configuration files inherit from the workspace-wide `tsconfig.*.json`, and app-specific [TSLint](https://palantir.github.io/tslint/) configuration files inherit from the workspace-wide `tslint.json`.
|
||||
|
||||
### Default app project files
|
||||
@ -40,9 +39,9 @@ This initial app is the *default app* for CLI commands (unless you change the de
|
||||
A newly generated app contains the source files for a root module, with a root component and template.
|
||||
When the workspace file structure is in place, you can use the `ng generate` command on the command line to add functionality and data to the initial app.
|
||||
|
||||
<div class="alert is-helpful>
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Besides using the CLI on the command line, You can also use an interactive development environment like [Angular Console](https://angular.console.com), or manipulate files directly in the app's source folder and configuration files.
|
||||
Besides using the CLI on the command line, you can also use an interactive development environment like [Angular Console](https://angularconsole.com/), or manipulate files directly in the app's source folder and configuration files.
|
||||
|
||||
</div>
|
||||
|
||||
@ -104,18 +103,6 @@ my-app/
|
||||
|
||||
Inside the `src/` folder, the `app/` folder contains your app's logic and data. Angular components, templates, and styles go here. An `assets/` subfolder contains images and anything else your app needs. Files at the top level of `src/` support testing and running your app.
|
||||
|
||||
<code-example language="none" linenums="false">
|
||||
src/
|
||||
app/
|
||||
app.component.css
|
||||
app.component.html
|
||||
app.component.spec.ts
|
||||
app.component.ts
|
||||
app.module.ts
|
||||
assets/...
|
||||
...
|
||||
</code-example>
|
||||
|
||||
| APP SOURCE FILES | PURPOSE |
|
||||
| :-------------------------- | :------------------------------------------|
|
||||
| `app/app.component.ts` | Defines the logic for the app's root component, named `AppComponent`. The view associated with this root component becomes the root of the [view hierarchy](guide/glossary#view-hierarchy) as you add components and services to your app. |
|
||||
|
@ -1,21 +1,21 @@
|
||||
# Introduction to forms in Angular
|
||||
|
||||
Handling user input with forms is the cornerstone of many common applications. Applications use forms to enable users log in, to update a profile, to enter sensitive information, and to perform many other data-entry tasks.
|
||||
Handling user input with forms is the cornerstone of many common applications. Applications use forms to enable users to log in, to update a profile, to enter sensitive information, and to perform many other data-entry tasks.
|
||||
|
||||
Angular provides two different approaches to handling user input through forms: reactive and template-driven. Both capture user input events from the view, validate the user input, create a form model and data model to update, and provide a way to track changes.
|
||||
|
||||
Reactive and template-driven forms differ, however, in how they do the work of processing and managing forms and form data. Each offers different advantages.
|
||||
Reactive and template-driven forms process and manage form data differently. Each offers different advantages.
|
||||
|
||||
**In general:**
|
||||
|
||||
* **Reactive forms** are more robust: they are more scalable, reusable, and testable. If forms are a key part of your application, or you're already using reactive patterns for building your application, use reactive forms.
|
||||
* **Template-driven forms** are useful for adding a simple form to an app, such as an email list signup form. They are easy to add to an app, but they do not scale as well as reactive forms. If you have very basic form requirements and logic that can be managed solely in the template, use template-driven forms.
|
||||
* **Reactive forms** are more robust: they're more scalable, reusable, and testable. If forms are a key part of your application, or you're already using reactive patterns for building your application, use reactive forms.
|
||||
* **Template-driven forms** are useful for adding a simple form to an app, such as an email list signup form. They're easy to add to an app, but they don't scale as well as reactive forms. If you have very basic form requirements and logic that can be managed solely in the template, use template-driven forms.
|
||||
|
||||
This guide provides information to help you decide which approach works best for your situation. It introduces the common building blocks used by both approaches. It also summarizes the key differences between the two approaches, and demonstrates those differences in the context of setup, data flow, and testing.
|
||||
This guide provides information to help you decide which type of form works best for your situation. It introduces the common building blocks used by both approaches. It also summarizes the key differences between the two approaches, and demonstrates those differences in the context of setup, data flow, and testing.
|
||||
|
||||
<div class="alert is-important">
|
||||
<div class="alert is-helpful">
|
||||
|
||||
*Note:* For complete information about each kind of form, see the [Reactive Forms](guide/reactive-forms) and [Template-driven Forms](guide/forms) guides.
|
||||
**Note:** For complete information about each kind of form, see [Reactive Forms](guide/reactive-forms) and [Template-driven Forms](guide/forms).
|
||||
|
||||
</div>
|
||||
|
||||
@ -30,7 +30,7 @@ The table below summarizes the key differences between reactive and template-dri
|
||||
|
||||
||Reactive|Template-driven|
|
||||
|--- |--- |--- |
|
||||
|Setup (form model)|More explicit, created in the component class.|Less explicit, created by the directives.|
|
||||
|Setup (form model)|More explicit, created in component class|Less explicit, created by directives|
|
||||
|Data model|Structured|Unstructured|
|
||||
|Predictability|Synchronous|Asynchronous|
|
||||
|Form validation|Functions|Directives|
|
||||
@ -41,35 +41,41 @@ The table below summarizes the key differences between reactive and template-dri
|
||||
|
||||
Both reactive and template-driven forms share underlying building blocks.
|
||||
|
||||
- A `FormControl` instance that tracks the value and validation status of an individual form control.
|
||||
- A `FormGroup` instance that tracks the same values and status for a collection of form controls.
|
||||
- A `FormArray` instance that tracks the same values and status for an array of form controls.
|
||||
- A `ControlValueAccessor` that creates a bridge between Angular `FormControl` instances and native DOM elements.
|
||||
|
||||
How these control instances are created and managed with reactive and template-driven forms is introduced in the [form model setup](#setup-the-form-model) section below and detailed further in the [data flow section](#data-flow-in-forms) of this guide.
|
||||
* `FormControl` tracks the value and validation status of an individual form control.
|
||||
|
||||
## Setup: The form model
|
||||
* `FormGroup` tracks the same values and status for a collection of form controls.
|
||||
|
||||
Reactive and template-driven forms both use a form model to track value changes between Angular forms and form input elements. The examples below show how the form model is defined and created.
|
||||
* `FormArray` tracks the same values and status for an array of form controls.
|
||||
|
||||
* `ControlValueAccessor` creates a bridge between Angular `FormControl` instances and native DOM elements.
|
||||
|
||||
See the [Form model setup](#setup-the-form-model) section below for an introduction to how these control instances are created and managed with reactive and template-driven forms. Further details are provided in the [data flow section](#data-flow-in-forms) of this guide.
|
||||
|
||||
{@a setup-the-form-model}
|
||||
|
||||
## Form model setup
|
||||
|
||||
Reactive and template-driven forms both use a form model to track value changes between Angular forms and form input elements. The examples below show how the form model is defined and created.
|
||||
|
||||
### Setup in reactive forms
|
||||
|
||||
Here is a component with an input field for a single control implemented using reactive forms.
|
||||
Here's a component with an input field for a single control implemented using reactive forms.
|
||||
|
||||
<code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.ts">
|
||||
</code-example>
|
||||
|
||||
The source of truth provides the value and status of the form element at a given point in time. In reactive forms, the form model is source of truth. The form model in the above example is the `FormControl` instance.
|
||||
The source of truth provides the value and status of the form element at a given point in time. In reactive forms, the form model is the source of truth. In the example above, the form model is the `FormControl` instance.
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/forms-overview/key-diff-reactive-forms.png" alt="Reactive forms key differences">
|
||||
</figure>
|
||||
|
||||
With reactive forms, the form model is explicitly defined in the component class. The reactive form directive (in this case, `FormControlDirective`) then links the existing form control instance to a specific form element in the view using a value accessor (instance of `ControlValueAccessor`).
|
||||
With reactive forms, the form model is explicitly defined in the component class. The reactive form directive (in this case, `FormControlDirective`) then links the existing `FormControl` instance to a specific form element in the view using a value accessor (`ControlValueAccessor` instance).
|
||||
|
||||
### Setup in template-driven forms
|
||||
|
||||
Here is the same component with an input field for a single control implemented using template-driven forms.
|
||||
Here's the same component with an input field for a single control implemented using template-driven forms.
|
||||
|
||||
<code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.ts">
|
||||
</code-example>
|
||||
@ -80,23 +86,25 @@ In template-driven forms, the source of truth is the template.
|
||||
<img src="generated/images/guide/forms-overview/key-diff-td-forms.png" alt="Template-driven forms key differences">
|
||||
</figure>
|
||||
|
||||
The abstraction of the form model promotes simplicity over structure. The template-driven form directive `NgModel` is responsible for creating and managing the form control instance for a given form element. It is less explicit, but you no longer have direct control over the form model.
|
||||
The abstraction of the form model promotes simplicity over structure. The template-driven form directive `NgModel` is responsible for creating and managing the `FormControl` instance for a given form element. It's less explicit, but you no longer have direct control over the form model.
|
||||
|
||||
{@a data-flow-in-forms}
|
||||
|
||||
## Data flow in forms
|
||||
|
||||
When building forms in Angular, it's important to understand how the framework handles data flowing from the user or from programmatic changes. Reactive and template-driven forms follow two different strategies when handling form input. The data flow examples below begin with the favorite color input field example from above, and they show how changes to favorite color are handled in reactive forms compared to template-driven forms.
|
||||
When building forms in Angular, it's important to understand how the framework handles data flowing from the user or from programmatic changes. Reactive and template-driven forms follow two different strategies when handling form input. The data flow examples below begin with the favorite color input field example from above, and then show how changes to favorite color are handled in reactive forms compared to template-driven forms.
|
||||
|
||||
### Data flow in reactive forms
|
||||
|
||||
As described above, in reactive forms each form element in the view is directly linked to a form model (`FormControl` instance). Updates from the view to model and model to view are synchronous and not dependent on the UI rendered. The diagrams below use the same favorite color example to demonstrate how data flows when an input field's value is changed from the view and then from the model.
|
||||
As described above, in reactive forms each form element in the view is directly linked to a form model (`FormControl` instance). Updates from the view to the model and from the model to the view are synchronous and aren't dependent on the UI rendered. The diagrams below use the same favorite color example to demonstrate how data flows when an input field's value is changed from the view and then from the model.
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/forms-overview/dataflow-reactive-forms-vtm.png" alt="Reactive forms data flow - view to model" width="100%">
|
||||
</figure>
|
||||
|
||||
The steps below outline the view to model data flow.
|
||||
The steps below outline the data flow from view to model.
|
||||
|
||||
1. The end user types a value into the input element, in this case the favorite color "Blue".
|
||||
1. The user types a value into the input element, in this case the favorite color *Blue*.
|
||||
1. The form input element emits an "input" event with the latest value.
|
||||
1. The control value accessor listening for events on the form input element immediately relays the new value to the `FormControl` instance.
|
||||
1. The `FormControl` instance emits the new value through the `valueChanges` observable.
|
||||
@ -106,37 +114,37 @@ The steps below outline the view to model data flow.
|
||||
<img src="generated/images/guide/forms-overview/dataflow-reactive-forms-mtv.png" alt="Reactive forms data flow - model to view" width="100%">
|
||||
</figure>
|
||||
|
||||
The steps below outline the model to view data flow.
|
||||
The steps below outline the data flow from model to view.
|
||||
|
||||
1. The `favoriteColorControl.setValue()` method is called, which updates the `FormControl` value.
|
||||
1. The user calls the `favoriteColorControl.setValue()` method, which updates the `FormControl` value.
|
||||
1. The `FormControl` instance emits the new value through the `valueChanges` observable.
|
||||
1. Any subscribers to the `valueChanges` observable receive the new value.
|
||||
1. The control value accessor on the form input element updates the element with the new value.
|
||||
|
||||
### Data flow in template-driven forms
|
||||
|
||||
In template-driven forms, each form element is linked to a directive that manages the form model internally. The diagrams below uses the same favorite color example to demonstrate how data flows when an input field's value is changed from the view and then from the model.
|
||||
In template-driven forms, each form element is linked to a directive that manages the form model internally. The diagrams below use the same favorite color example to demonstrate how data flows when an input field's value is changed from the view and then from the model.
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/forms-overview/dataflow-td-forms-vtm.png" alt="Template-driven forms view to model data flow" width="100%">
|
||||
<img src="generated/images/guide/forms-overview/dataflow-td-forms-vtm.png" alt="Template-driven forms data flow - view to model" width="100%">
|
||||
</figure>
|
||||
|
||||
The steps below outline the view to model data flow.
|
||||
The steps below outline the data flow from view to model when the input value changes from *Red* to *Blue*.
|
||||
|
||||
1. The end user types "Blue" into the input element.
|
||||
1. The input element emits an "input" event with the value "Blue".
|
||||
1. The user types *Blue* into the input element.
|
||||
1. The input element emits an "input" event with the value *Blue*.
|
||||
1. The control value accessor attached to the input triggers the `setValue()` method on the `FormControl` instance.
|
||||
1. The `FormControl` instance emits the new value through the `valueChanges` observable.
|
||||
1. Any subscribers to the `valueChanges` observable receive the new value.
|
||||
1. The control value accessor also calls the `NgModel.viewToModel()` method which emits an `ngModelChange` event.
|
||||
1. Because the component template uses two-way data binding for the `favoriteColor`, the `favoriteColor` property in the component
|
||||
is updated to the value emitted by the `ngModelChange` event ("Blue").
|
||||
1. The control value accessor also calls the `NgModel.viewToModelUpdate()` method which emits an `ngModelChange` event.
|
||||
1. Because the component template uses two-way data binding for the `favoriteColor` property, the `favoriteColor` property in the component
|
||||
is updated to the value emitted by the `ngModelChange` event (*Blue*).
|
||||
|
||||
<figure>
|
||||
<img src="generated/images/guide/forms-overview/dataflow-td-forms-mtv.png" alt="Template-driven forms model to view data flow" width="100%">
|
||||
<img src="generated/images/guide/forms-overview/dataflow-td-forms-mtv.png" alt="Template-driven forms data flow - model to view" width="100%">
|
||||
</figure>
|
||||
|
||||
The steps below outline the model to view data flow.
|
||||
The steps below outline the data flow from model to view when the `favoriteColor` changes from *Blue* to *Red*.
|
||||
|
||||
1. The `favoriteColor` value is updated in the component.
|
||||
1. Change detection begins.
|
||||
@ -150,110 +158,117 @@ The steps below outline the model to view data flow.
|
||||
|
||||
## Form validation
|
||||
|
||||
Validation is an integral part of managing any set of forms. Whether you’re checking for required fields or querying an external API for an existing username, Angular provides a set of built-in validators as well as the ability to create custom validators.
|
||||
Validation is an integral part of managing any set of forms. Whether you're checking for required fields or querying an external API for an existing username, Angular provides a set of built-in validators as well as the ability to create custom validators.
|
||||
|
||||
* **Reactive forms** define custom validators as **functions** that receive a control to validate.
|
||||
* **Template-driven forms** are tied to template **directives**, and must provide custom validator directives that wrap validation functions.
|
||||
|
||||
For more on form validation, see the [Form Validation](guide/form-validation) guide.
|
||||
For more information, see [Form Validation](guide/form-validation).
|
||||
|
||||
## Testing
|
||||
|
||||
Testing also plays a large part in complex applications and an easier testing strategy is always welcomed. One difference in testing reactive forms and template-driven forms is their reliance on rendering the UI in order to perform assertions based on form control and form field changes. The following examples demonstrate the process of testing forms with reactive and template-driven forms.
|
||||
Testing plays a large part in complex applications and a simpler testing strategy is useful when validating that your forms function correctly. Reactive forms and template-driven forms have different levels of reliance on rendering the UI to perform assertions based on form control and form field changes. The following examples demonstrate the process of testing forms with reactive and template-driven forms.
|
||||
|
||||
### Testing reactive forms
|
||||
|
||||
Reactive forms provide a relatively easy testing strategy because they provide synchronous access to the form and data models, and they can be tested without rendering the UI. In these set of tests, controls and data are queried and manipulated through the control without interacting with the change detection cycle.
|
||||
Reactive forms provide a relatively easy testing strategy because they provide synchronous access to the form and data models, and they can be tested without rendering the UI. In these tests, status and data are queried and manipulated through the control without interacting with the change detection cycle.
|
||||
|
||||
The following tests use the favorite color components mentioned earlier to verify the view to model and model to view data flows for a reactive form.
|
||||
The following tests use the favorite color components mentioned earlier to verify the data flows from view to model and model to view for a reactive form.
|
||||
|
||||
The following test verifies the view to model data flow:
|
||||
The following test verifies the data flow from view to model.
|
||||
|
||||
<code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.spec.ts" region="view-to-model" header="Favorite color test - view to model">
|
||||
</code-example>
|
||||
|
||||
The steps performed in the view to model test.
|
||||
Here are the steps performed in the view to model test.
|
||||
|
||||
1. Query the view for the form input element, and create a custom "input" event for the test.
|
||||
1. Set the new value for the input is set to *Red*, and dispatch the "input" event on the form input element.
|
||||
1. Assert that the `favoriteColor` `FormControl` instance value matches the value from the input.
|
||||
1. Set the new value for the input to *Red*, and dispatch the "input" event on the form input element.
|
||||
1. Assert that the component's `favoriteColorControl` value matches the value from the input.
|
||||
|
||||
The following test verifies the model to view data flow:
|
||||
The following test verifies the data flow from model to view.
|
||||
|
||||
<code-example path="forms-overview/src/app/reactive/favorite-color/favorite-color.component.spec.ts" region="model-to-view" header="Favorite color test - model to view">
|
||||
</code-example>
|
||||
|
||||
The steps performed in the model to view test.
|
||||
Here are the steps performed in the model to view test.
|
||||
|
||||
1. Use the `favoriteColor` `FormControl` instance to set the new value.
|
||||
1. Use the `favoriteColorControl`, a `FormControl` instance, to set the new value.
|
||||
1. Query the view for the form input element.
|
||||
1. Assert that the new value set on the control matches the value in the input.
|
||||
|
||||
### Testing template-driven forms
|
||||
|
||||
Writing tests with template-driven forms requires more detailed knowledge of the change detection process and how directives run on each cycle to ensure elements are queried, tested, or changed at the correct time.
|
||||
Writing tests with template-driven forms requires a detailed knowledge of the change detection process and an understanding of how directives run on each cycle to ensure that elements are queried, tested, or changed at the correct time.
|
||||
|
||||
The following tests use the favorite color components mentioned earlier to verify the view to model and model to view data flows for a template-driven form.
|
||||
The following tests use the favorite color components mentioned earlier to verify the data flows from view to model and model to view for a template-driven form.
|
||||
|
||||
The following test verifies the view to model data flow:
|
||||
The following test verifies the data flow from view to model.
|
||||
|
||||
<code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.spec.ts" region="view-to-model" header="Favorite color test - view to model">
|
||||
</code-example>
|
||||
|
||||
The steps performed in the view to model test.
|
||||
Here are the steps performed in the view to model test.
|
||||
|
||||
1. Query the view for the form input element, and create a custom "input" event for the test.
|
||||
1. Set the new value for the input is set to *Red*, and dispatch the "input" event on the form input element.
|
||||
1. Set the new value for the input to *Red*, and dispatch the "input" event on the form input element.
|
||||
1. Run change detection through the test fixture.
|
||||
1. Assert that the component `favoriteColor` property value matches the value from the input.
|
||||
|
||||
The following test verifies the model to view data flow:
|
||||
The following test verifies the data flow from model to view.
|
||||
|
||||
<code-example path="forms-overview/src/app/template/favorite-color/favorite-color.component.spec.ts" region="model-to-view" header="Favorite color test - model to view">
|
||||
</code-example>
|
||||
|
||||
The steps performed in the model to view test.
|
||||
Here are the steps performed in the model to view test.
|
||||
|
||||
1. Use the component instance to set the value of `favoriteColor` property.
|
||||
1. Use the component instance to set the value of the `favoriteColor` property.
|
||||
1. Run change detection through the test fixture.
|
||||
1. Use the `tick()` method to simulate passage of time within the `fakeAsync()` task.
|
||||
1. Use the `tick()` method to simulate the passage of time within the `fakeAsync()` task.
|
||||
1. Query the view for the form input element.
|
||||
1. Assert that the input value matches the `favoriteColor` value property in the component instance.
|
||||
1. Assert that the input value matches the value of the `favoriteColor` property in the component instance.
|
||||
|
||||
## Mutability
|
||||
|
||||
How changes are tracked plays a role in the efficiency of your application.
|
||||
The change tracking method plays a role in the efficiency of your application.
|
||||
|
||||
- **Reactive forms** keep the data model pure by providing it as an immutable data structure. Each time a change is triggered on the data model, the `FormControl` instance returns a new data model rather than updating the data model directly. This gives you the ability track unique changes to the data model through the control's observable. This allows change detection to be more efficient because it only needs to update on unique changes. It also follows reactive patterns that integrate with observable operators to transform data.
|
||||
- **Template-driven** forms rely on mutability with two-way data binding to update the data model in the component as changes are made in the template. Because there are no unique changes to track on the data model when using two-way data binding, change detection is less efficient at determining when updates are required.
|
||||
|
||||
* **Reactive forms** keep the data model pure by providing it as an immutable data structure. Each time a change is triggered on the data model, the `FormControl` instance returns a new data model rather than updating the existing data model. This gives you the ability to track unique changes to the data model through the control's observable. This provides one way for change detection to be more efficient because it only needs to update on unique changes. It also follows reactive patterns that integrate with observable operators to transform data.
|
||||
|
||||
* **Template-driven** forms rely on mutability with two-way data binding to update the data model in the component as changes are made in the template. Because there are no unique changes to track on the data model when using two-way data binding, change detection is less efficient at determining when updates are required.
|
||||
|
||||
The difference is demonstrated in the examples above using the **favorite color** input element.
|
||||
|
||||
- With reactive forms, the **`FormControl` instance** always returns a new value when the control's value is updated.
|
||||
- With template-driven forms, the **favorite color property** is always modified to its new value.
|
||||
|
||||
* With reactive forms, the **`FormControl` instance** always returns a new value when the control's value is updated.
|
||||
|
||||
* With template-driven forms, the **favorite color property** is always modified to its new value.
|
||||
|
||||
## Scalability
|
||||
|
||||
If forms are a central part of your application, scalability is very important. Being able to reuse form models across components is critical.
|
||||
|
||||
- **Reactive forms** make creating large scale forms easier by providing access to low-level APIs and synchronous access to the form model.
|
||||
- **Template-driven** forms focus on simple scenarios, are not as reusable, abstract away the low-level APIs and access to the form model is provided asynchronously. The abstraction with template-driven forms surfaces in testing also, where testing reactive forms requires less setup and no dependence on the change detection cycle when updating and validating the form and data models during testing.
|
||||
|
||||
## Final Thoughts
|
||||
* **Reactive forms** provide access to low-level APIs and synchronous access to the form model, making creating large-scale forms easier.
|
||||
|
||||
Choosing a strategy begins with understanding the strengths and weaknesses of the options presented. Low-level API and form model access, predictability, mutability, straightforward validation and testing strategies, and scalability are all important consideration in choosing the infrastructure you use when building your forms in Angular. Template-driven forms are similar to patterns in AngularJS, but they have limitations given the criteria of many modern, large-scale Angular apps. Reactive forms integrate with reactive patterns already present in other areas of the Angular architecture, and complement those requirements well. Those limitations are alleviated with reactive forms.
|
||||
* **Template-driven** forms focus on simple scenarios, are not as reusable, abstract away the low-level APIs, and provide asynchronous access to the form model. The abstraction with template-driven forms also surfaces in testing, where testing reactive forms requires less setup and no dependence on the change detection cycle when updating and validating the form and data models during testing.
|
||||
|
||||
## Final thoughts
|
||||
|
||||
Choosing a strategy begins with understanding the strengths and weaknesses of the options presented. Low-level API and form model access, predictability, mutability, straightforward validation and testing strategies, and scalability are all important considerations in choosing the infrastructure you use to build your forms in Angular. Template-driven forms are similar to patterns in AngularJS, but they have limitations given the criteria of many modern, large-scale Angular apps. Reactive forms minimize these limitations. Reactive forms integrate with reactive patterns already present in other areas of the Angular architecture, and complement those requirements well.
|
||||
|
||||
## Next steps
|
||||
|
||||
## Next Steps
|
||||
|
||||
The following guides are the next steps in the learning process.
|
||||
|
||||
To learn more about reactive forms, see the following guides:
|
||||
|
||||
* [Reactive Forms](guide/reactive-forms)
|
||||
* [Form Validation](guide/form-validation#reactive-form-validation)
|
||||
* [Dynamic forms](guide/dynamic-form)
|
||||
* [Dynamic Forms](guide/dynamic-form)
|
||||
|
||||
To learn more about template-driven forms, see the following guides:
|
||||
|
||||
* [Template-driven Forms](guide/forms)
|
||||
* [Template-driven Forms](guide/forms#template-driven-forms)
|
||||
* [Form Validation](guide/form-validation#template-driven-validation)
|
||||
|
||||
|
@ -672,7 +672,7 @@ format that Angular understands, such as `.xtb`.
|
||||
How you provide this information depends upon whether you compile with
|
||||
the JIT compiler or the AOT compiler.
|
||||
|
||||
* With [AOT](guide/i18n#merge-aot), you pass the information as a configuration
|
||||
* With [AOT](guide/i18n#merge-aot), you pass the information as configuration settings.
|
||||
* With [JIT](guide/i18n#merge-jit), you provide the information at bootstrap time.
|
||||
|
||||
|
||||
|
@ -1,173 +1,141 @@
|
||||
# Npm Packages
|
||||
# Workspace npm dependencies
|
||||
|
||||
The [**Angular CLI**](https://cli.angular.io/), Angular applications, and Angular itself depend upon features and functionality provided by libraries that are available as [**npm**](https://docs.npmjs.com/) packages.
|
||||
The Angular Framework, Angular CLI, and components used by Angular applications are packaged as [npm packages](https://docs.npmjs.com/getting-started/what-is-npm "What is npm?") and distributed via the [npm registry](https://docs.npmjs.com/).
|
||||
|
||||
You can download and install these npm packages with the [**npm client**](https://docs.npmjs.com/cli/install), which runs as a Node.js® application.
|
||||
You can download and install these npm packages by using the [npm CLI client](https://docs.npmjs.com/cli/install), which is installed with and runs as a [Node.js®](https://nodejs.org "Nodejs.org") application. By default, the Angular CLI uses the npm client.
|
||||
|
||||
Alternatively, you can use the [yarn client](https://yarnpkg.com/) for downloading and installing npm packages.
|
||||
|
||||
The [**yarn client**](https://yarnpkg.com/en/) is a popular alternative for downloading and installing npm packages.
|
||||
The Angular CLI uses `yarn` by default to install npm packages when you create a new project.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Node.js and npm are essential to Angular development.
|
||||
See [Getting Started](guide/quickstart#prerequisites) for information about the required versions and installation of Node.js and npm.
|
||||
|
||||
[Get them now](https://docs.npmjs.com/getting-started/installing-node "Installing Node.js and updating npm")
|
||||
if they're not already installed on your machine.
|
||||
|
||||
**Verify that you are running Node.js `v8.x` or higher and npm `5.x` or higher**
|
||||
by running the commands `node -v` and `npm -v` in a terminal/console window.
|
||||
Older versions produce errors.
|
||||
|
||||
Consider using [nvm](https://github.com/creationix/nvm) for managing multiple
|
||||
versions of Node.js and npm. You may need [nvm](https://github.com/creationix/nvm) if
|
||||
you already have projects running on your machine that use other versions of Node.js and npm.
|
||||
If you already have projects running on your machine that use other versions of Node.js and npm, consider using [nvm](https://github.com/creationix/nvm) to manage the multiple versions of Node.js and npm.
|
||||
|
||||
</div>
|
||||
|
||||
## _package.json_
|
||||
|
||||
Both `npm` and `yarn` install packages that are identified in a [**package.json**](https://docs.npmjs.com/files/package.json) file.
|
||||
## `package.json`
|
||||
|
||||
The CLI `ng new` command creates a default `package.json` file for your project.
|
||||
This `package.json` specifies _a starter set of packages_ that work well together and
|
||||
jointly support many common application scenarios.
|
||||
Both `npm` and `yarn` install the packages that are identified in a [`package.json`](https://docs.npmjs.com/files/package.json) file.
|
||||
|
||||
You will add packages to `package.json` as your application evolves.
|
||||
You may even remove some.
|
||||
The CLI command `ng new` creates a `package.json` file when it creates the new workspace.
|
||||
This `package.json` is used by all projects in the workspace, including the initial app project that is created by the CLI when it creates the workspace.
|
||||
|
||||
This guide focuses on the most important packages in the starter set.
|
||||
Initially, this `package.json` includes _a starter set of packages_, some of which are required by Angular and others that support common application scenarios.
|
||||
You add packages to `package.json` as your application evolves.
|
||||
You may even remove some.
|
||||
|
||||
#### *dependencies* and *devDependencies*
|
||||
The `package.json` is organized into two groups of packages:
|
||||
|
||||
The `package.json` includes two sets of packages,
|
||||
[dependencies](guide/npm-packages#dependencies) and [devDependencies](guide/npm-packages#dev-dependencies).
|
||||
* [Dependencies](guide/npm-packages#dependencies) are essential to *running* applications.
|
||||
* [DevDependencies](guide/npm-packages#dev-dependencies) are only necessary to *develop* applications.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Library developers:** By default, the CLI command [`ng generate library`](cli/generate) creates a `package.json` for the new library. That `package.json` is used when publishing the library to npm.
|
||||
For more information, see the CLI wiki page [Library Support](https://github.com/angular/angular-cli/wiki/stories-create-library).
|
||||
</div>
|
||||
|
||||
The *dependencies* are essential to *running* the application.
|
||||
The *devDependencies* are only necessary to *develop* the application.
|
||||
|
||||
{@a dependencies}
|
||||
## Dependencies
|
||||
|
||||
The packages listed in the `dependencies` section of `package.json` are essential to *running* applications.
|
||||
|
||||
## *Dependencies*
|
||||
The `dependencies` section of `package.json` contains:
|
||||
|
||||
* **Angular packages**: Angular core and optional modules; their package names begin `@angular/`.
|
||||
* [**Angular packages**](#angular-packages): Angular core and optional modules; their package names begin `@angular/`.
|
||||
|
||||
* **Support packages**: 3rd party libraries that must be present for Angular apps to run.
|
||||
* [**Support packages**](#support-packages): 3rd party libraries that must be present for Angular apps to run.
|
||||
|
||||
* **Polyfill packages**: Polyfills plug gaps in a browser's JavaScript implementation.
|
||||
* [**Polyfill packages**](#polyfills): Polyfills plug gaps in a browser's JavaScript implementation.
|
||||
|
||||
### Angular Packages
|
||||
To add a new dependency, use the [`ng add`](cli/add) command.
|
||||
|
||||
**@angular/animations**: Angular's animations library makes it easy to define and apply animation effects such as page and list transitions.
|
||||
Read about it in the [Animations guide](guide/animations).
|
||||
{@a angular-packages}
|
||||
### Angular packages
|
||||
|
||||
**@angular/common**: The commonly needed services, pipes, and directives provided by the Angular team.
|
||||
The [`HttpClientModule`](guide/http) is also here, in the '@angular/common/http' subfolder.
|
||||
The following Angular packages are included as dependencies in the default `package.json` file for a new Angular workspace.
|
||||
For a complete list of Angular packages, see the [API reference](http://angular.io/api?type=package).
|
||||
|
||||
**@angular/core**: Critical runtime parts of the framework needed by every application.
|
||||
Includes all metadata decorators, `Component`, `Directive`, dependency injection, and the component lifecycle hooks.
|
||||
Package name | Description
|
||||
---------------------------------------- | --------------------------------------------------
|
||||
[**@angular/animations**](api/animations) | Angular's animations library makes it easy to define and apply animation effects such as page and list transitions. For more information, see the [Animations guide](guide/animations).
|
||||
[**@angular/common**](api/common) | The commonly-needed services, pipes, and directives provided by the Angular team. The [`HttpClientModule`](api/common/http/HttpClientModule) is also here, in the [`@angular/common/http`](api/common/http) subfolder. For more information, see the [HttpClient guide](guide/http).
|
||||
**@angular/compiler** | Angular's template compiler. It understands templates and can convert them to code that makes the application run and render. Typically you don’t interact with the compiler directly; rather, you use it indirectly via `platform-browser-dynamic` when JIT compiling in the browser. For more information, see the [Ahead-of-time Compilation guide](guide/aot-compiler).
|
||||
[**@angular/core**](api/core) | Critical runtime parts of the framework that are needed by every application. Includes all metadata decorators, `Component`, `Directive`, dependency injection, and the component lifecycle hooks.
|
||||
[**@angular/forms**](api/forms) | Support for both [template-driven](guide/forms) and [reactive forms](guide/reactive-forms). For information about choosing the best forms approach for your app, see [Introduction to forms](guide/forms-overview).
|
||||
[**@angular/http**](api/http) | Angular's legacy HTTP client, which was deprecated in version 5.0 in favor of [@angular/common/http](api/common/http).
|
||||
[**@angular/<br />platform‑browser**](api/platform-browser) | Everything DOM and browser related, especially the pieces that help render into the DOM. This package also includes the `bootstrapModuleFactory()` method for bootstrapping applications for production builds that pre-compile with [AOT](guide/aot-compiler).
|
||||
[**@angular/<br />platform‑browser‑dynamic**](api/platform-browser-dynamic) | Includes [providers](api/core/Provider) and methods to compile and run the app on the client using the [JIT compiler](guide/aot-compiler).
|
||||
[**@angular/router**](api/router) | The router module navigates among your app pages when the browser URL changes. For more information, see [Routing and Navigation](guide/router).
|
||||
|
||||
**@angular/compiler**: Angular's *Template Compiler*.
|
||||
It understands templates and can convert them to code that makes the application run and render.
|
||||
Typically you don’t interact with the compiler directly; rather, you use it indirectly via `platform-browser-dynamic` when [JIT compiling](guide/aot-compiler) in the browser.
|
||||
|
||||
**@angular/forms**: support for both [template-driven](guide/forms) and [reactive forms](guide/reactive-forms).
|
||||
{@a support-packages}
|
||||
### Support packages
|
||||
|
||||
**@angular/http**: Angular's old, deprecated, HTTP client.
|
||||
The following support packages are included as dependencies in the default `package.json` file for a new Angular workspace.
|
||||
|
||||
**@angular/platform-browser**: Everything DOM and browser related, especially
|
||||
the pieces that help render into the DOM.
|
||||
This package also includes the `bootstrapModuleFactory()` method
|
||||
for bootstrapping applications for production builds that pre-compile with [AOT](guide/aot-compiler).
|
||||
|
||||
**@angular/platform-browser-dynamic**: Includes [Providers](api/core/Provider)
|
||||
and methods to compile and run the app on the client
|
||||
using the [JIT compiler](guide/aot-compiler).
|
||||
Package name | Description
|
||||
---------------------------------------- | --------------------------------------------------
|
||||
[**rxjs**](https://github.com/ReactiveX/rxjs) | Many Angular APIs return [_observables_](guide/glossary#observable). RxJS is an implementation of the proposed [Observables specification](https://github.com/tc39/proposal-observable) currently before the [TC39](https://www.ecma-international.org/memento/tc39-m.htm) committee, which determines standards for the JavaScript language.
|
||||
[**zone.js**](https://github.com/angular/zone.js) | Angular relies on zone.js to run Angular's change detection processes when native JavaScript operations raise events. Zone.js is an implementation of a [specification](https://gist.github.com/mhevery/63fdcdf7c65886051d55) currently before the [TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
|
||||
|
||||
**@angular/router**: The [router module](/guide/router) navigates among your app pages when the browser URL changes.
|
||||
|
||||
**@angular/upgrade**: Set of utilities for upgrading AngularJS applications to Angular.
|
||||
|
||||
{@a polyfills}
|
||||
|
||||
### Polyfill packages
|
||||
|
||||
Many browsers lack native support for some features in the latest HTML standards,
|
||||
features that Angular requires.
|
||||
"[Polyfills](https://en.wikipedia.org/wiki/Polyfill)" can emulate the missing features.
|
||||
[_Polyfills_](https://en.wikipedia.org/wiki/Polyfill) can emulate the missing features.
|
||||
The [Browser Support](guide/browser-support) guide explains which browsers need polyfills and
|
||||
how you can add them.
|
||||
|
||||
The default `package.json` installs the **[core-js](https://github.com/zloirock/core-js)** package
|
||||
The `package.json` for a new Angular workspace installs the [core-js](https://github.com/zloirock/core-js) package,
|
||||
which polyfills missing features for several popular browser.
|
||||
|
||||
### Support packages
|
||||
|
||||
**[rxjs](https://github.com/benlesh/RxJS)**: Many Angular APIs return _observables_. RxJS is an implementation of the proposed [Observables specification](https://github.com/zenparsing/es-observable) currently before the
|
||||
[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
|
||||
|
||||
|
||||
**[zone.js](https://github.com/angular/zone.js)**: Angular relies on zone.js to run Angular's change detection processes when native JavaScript operations raise events. Zone.js is an implementation of a [specification](https://gist.github.com/mhevery/63fdcdf7c65886051d55) currently before the
|
||||
[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
|
||||
|
||||
|
||||
{@a dev-dependencies}
|
||||
|
||||
## *DevDependencies*
|
||||
## DevDependencies
|
||||
|
||||
The packages listed in the *devDependencies* section of the `package.json` help you develop the application on your local machine.
|
||||
The packages listed in the `devDependencies` section of `package.json` help you develop the application on your local machine. You don't deploy them with the production application.
|
||||
|
||||
You don't deploy them with the production application although there is no harm in doing so.
|
||||
To add a new `devDependency`, use either one of the following commands:
|
||||
|
||||
**[@angular/cli](https://github.com/angular/angular-cli/)**: The Angular CLI tools.
|
||||
<code-example language="sh" class="code-shell">
|
||||
npm install --dev <package-name>
|
||||
</code-example>
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
yarn add --dev <package-name>
|
||||
</code-example>
|
||||
|
||||
The following `devDependencies` are provided in the default `package.json` file for a new Angular workspace.
|
||||
|
||||
|
||||
**[@angular/compiler-cli](https://github.com/angular/angular/blob/master/packages/compiler-cli/README.md)**: The Angular compiler, which is invoked by the Angular CLI's `build` and `serve` commands.
|
||||
Package name | Description
|
||||
---------------------------------------- | -----------------------------------
|
||||
[**@angular‑devkit/<br />build‑angular**](https://github.com/angular/angular-cli/) | The Angular build tools.
|
||||
[**@angular/cli**](https://github.com/angular/angular-cli/) | The Angular CLI tools.
|
||||
**@angular/<br />compiler‑cli** | The Angular compiler, which is invoked by the Angular CLI's `ng build` and `ng serve` commands.
|
||||
**@angular/<br />language‑service** | The [Angular language service](guide/language-service) analyzes component templates and provides type and error information that TypeScript-aware editors can use to improve the developer's experience. For example, see the [Angular language service extension for VS Code](https://marketplace.visualstudio.com/items?itemName=Angular.ng-template).
|
||||
**@types/... ** | TypeScript definition files for 3rd party libraries such as Jasmine and Node.js.
|
||||
[**codelyzer**](https://www.npmjs.com/package/codelyzer) | A linter for Angular apps whose rules conform to the Angular [style guide](guide/styleguide).
|
||||
**jasmine/... ** | Packages to support the [Jasmine](https://jasmine.github.io/) test library.
|
||||
**karma/... ** | Packages to support the [karma](https://www.npmjs.com/package/karma) test runner.
|
||||
[**protractor**](https://www.npmjs.com/package/protractor) | An end-to-end (e2e) framework for Angular apps. Built on top of [WebDriverJS](https://github.com/SeleniumHQ/selenium/wiki/WebDriverJs).
|
||||
[**ts-node**](https://www.npmjs.com/package/ts-node) | TypeScript execution environment and REPL for Node.js.
|
||||
[**tslint**](https://www.npmjs.com/package/tslint) | A static analysis tool that checks TypeScript code for readability, maintainability, and functionality errors.
|
||||
[**typescript**](https://www.npmjs.com/package/typescript) | The TypeScript language server, including the *tsc* TypeScript compiler.
|
||||
|
||||
|
||||
**[@angular/language-service](https://github.com/angular/angular-cli/)**: The Angular language service analyzes component templates and provides type and error information that TypeScript-aware editors can use to improve the developer's experience.
|
||||
For example, see the [Angular language service extension for VS Code](https://marketplace.visualstudio.com/items?itemName=Angular.ng-template)
|
||||
## Related information
|
||||
|
||||
|
||||
**@types/... **: TypeScript definition files for 3rd party libraries such as Jasmine and Node.js.
|
||||
|
||||
|
||||
**[codelyzer](https://www.npmjs.com/package/codelyzer)**: A linter for Angular apps whose rules conform to the Angular [style guide](guide/styleguide).
|
||||
|
||||
|
||||
**jasmine/... **: packages to support the [Jasmine](https://jasmine.github.io/) test library.
|
||||
|
||||
|
||||
**karma/... **: packages to support the [karma](https://www.npmjs.com/package/karma) test runner.
|
||||
|
||||
|
||||
**[protractor](https://www.npmjs.com/package/protractor)**: an end-to-end (e2e) framework for Angular apps.
|
||||
Built on top of [WebDriverJS](https://github.com/SeleniumHQ/selenium/wiki/WebDriverJs).
|
||||
|
||||
|
||||
**[ts-node](https://www.npmjs.com/package/ts-node)**: TypeScript execution environment and REPL for Node.js.
|
||||
|
||||
|
||||
**[tslint](https://www.npmjs.com/package/tslint)**: a static analysis tool that checks TypeScript code for readability, maintainability, and functionality errors.
|
||||
|
||||
|
||||
**[typescript](https://www.npmjs.com/package/typescript)**:
|
||||
the TypeScript language server, including the *tsc* TypeScript compiler.
|
||||
|
||||
|
||||
## So many packages! So many files!
|
||||
|
||||
The default `package.json` installs more packages than you'll need for your project.
|
||||
|
||||
A given package may contain tens, hundreds, even thousands of files,
|
||||
all of them in your local machine's `node_modules` directory.
|
||||
The sheer volume of files is intimidating,
|
||||
|
||||
You can remove packages that you don't need but how can you be sure that you won't need it?
|
||||
As a practical matter, it's better to install a package you don't need than worry about it.
|
||||
Extra packages and package files on your local development machine are harmless.
|
||||
|
||||
By default the Angular CLI build process bundles into a single file just the few "vendor" library files that your application actually needs.
|
||||
The browser downloads this bundle, not the original package files.
|
||||
|
||||
See the [Deployment](guide/deployment) to learn more.
|
||||
For information about how the Angular CLI handles packages see the following guides:
|
||||
|
||||
* [Building and serving](guide/build) describes how packages come together to create a development build.
|
||||
* [Deployment](guide/deployment) describes how packages come together to create a production build.
|
||||
|
@ -65,68 +65,34 @@ Disclaimer: The dates are offered as general guidance and may be adjusted by us
|
||||
|
||||
The following table contains our current target release dates for the next two major versions of Angular:
|
||||
|
||||
Date | Stable Release | Compatibility
|
||||
---------------------- | -------------- | ----------------
|
||||
September/October 2018 | 7.0.0 | ^6.0.0
|
||||
Date | Stable Release | Compatibility
|
||||
---------------------- | -------------- | -------------
|
||||
March/April 2019 | 8.0.0 | ^7.0.0
|
||||
September/October 2019 | 9.0.0 | ^8.0.0
|
||||
|
||||
Compatibility note: The primary goal of the backward compatibility promise is to ensure that changes in the core framework and tooling don't break the existing ecosystem of components and applications and don't put undue upgrade/migration burden on Angular application and component authors.
|
||||
|
||||
|
||||
{@a lts}
|
||||
{@a support}
|
||||
## Support policy
|
||||
## Support policy and schedule
|
||||
|
||||
All of our major releases are supported for 18 months.
|
||||
|
||||
* 6 months of active support, during which regularly-scheduled updates and patches are released, as described above in [Release frequency](#frequency "Release frequency").
|
||||
* 6 months of *active support*, during which regularly-scheduled updates and patches are released.
|
||||
|
||||
* 12 months of long-term support (LTS). During the LTS period, only critical fixes and security patches will be released.
|
||||
* 12 months of *long-term support (LTS)*, during which only critical fixes and security patches are released.
|
||||
|
||||
The following table provides the support status and key dates for Angular version 4.0.0 and higher.
|
||||
The following table provides the support status and key dates for Angular version 5.0.0 and higher.
|
||||
|
||||
<style>
|
||||
|
||||
td, th {vertical-align: top}
|
||||
|
||||
</style>
|
||||
|
||||
<table>
|
||||
|
||||
<tr>
|
||||
<th>Version</th>
|
||||
<th>Status</th>
|
||||
<th>Release Date</th>
|
||||
<th>LTS Start Date</th>
|
||||
<th>LTS End Date</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>^4.0.0</td>
|
||||
<td>LTS</td>
|
||||
<td>March 23, 2017</td>
|
||||
<td>September 23, 2017</td>
|
||||
<td>September 23, 2018</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>^5.0.0</td>
|
||||
<td>LTS</td>
|
||||
<td>November 1, 2017</td>
|
||||
<td>May 1, 2018</td>
|
||||
<td>May 1, 2019</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>^6.0.0</td>
|
||||
<td>Active</td>
|
||||
<td>May 3, 2018</td>
|
||||
<td>November 3, 2018</td>
|
||||
<td>November 3, 2019</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
Version | Status | Released | Active Ends | LTS Ends
|
||||
------- | ------ | ------------ | ------------ | ------------
|
||||
^7.0.0 | Active | Oct 18, 2018 | Apr 18, 2019 | Apr 18, 2020
|
||||
^6.0.0 | LTS | May 3, 2018 | Nov 3, 2018 | Nov 3, 2019
|
||||
^5.0.0 | LTS | Nov 1, 2017 | May 1, 2018 | May 1, 2019
|
||||
|
||||
LTS for Angular version ^4.0.0 ended on September 23, 2018.
|
||||
|
||||
|
||||
{@a deprecation}
|
||||
|
@ -161,7 +161,15 @@ This section defines the policy by which matching requests will be cached.
|
||||
For example, the string `3d12h` will cache content for up to three and a half days.
|
||||
|
||||
#### `timeout`
|
||||
This duration string specifies the network timeout. The network timeout is how long the Angular service worker will wait for the network to respond before using a cached response, if configured to do so.
|
||||
This duration string specifies the network timeout. The network timeout is how long the Angular service worker will wait for the network to respond before using a cached response, if configured to do so. `timeout` is a duration string, using the following unit suffixes:
|
||||
|
||||
* `d`: days
|
||||
* `h`: hours
|
||||
* `m`: minutes
|
||||
* `s`: seconds
|
||||
* `u`: milliseconds
|
||||
|
||||
For example, the string `5s30u` will translate to five seconds and 30 milliseconds of network timeout.
|
||||
|
||||
#### `strategy`
|
||||
|
||||
|
@ -31,7 +31,7 @@ Installing the Angular service worker is as simple as including an `NgModule`. I
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Your application must run in a web browser that supports service workers. Currently, the latest versions of Chrome and Firefox are supported. To learn about other browsers that are service worker ready, see the [Can I Use](http://caniuse.com/#feat=serviceworkers) page.
|
||||
Your application must run in a web browser that supports service workers. Currently, service workers are supported in the latest versions of Chrome, Firefox, Edge, Safari, Opera, UC Browser (Android version) and Samsung Internet. Browsers like IE and Opera Mini do not provide the support. To learn more about other browsers that are service worker ready, see the [Can I Use](https://caniuse.com/#feat=serviceworkers) page and [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API).
|
||||
|
||||
## Related resources
|
||||
|
||||
|
@ -23,7 +23,7 @@ Just run the [`ng test`](cli/test) CLI command:
|
||||
</code-example>
|
||||
|
||||
The `ng test` command builds the app in _watch mode_,
|
||||
and launches the [karma test runner](https://karma-runner.github.io/1.0/index.html).
|
||||
and launches the [karma test runner](https://karma-runner.github.io).
|
||||
|
||||
The console output looks a bit like this:
|
||||
|
||||
@ -184,7 +184,7 @@ You'll need to push a new commit to trigger a build.
|
||||
|
||||
When the CLI commands `ng test` and `ng e2e` are generally running the CI tests in your environment, you might still need to adjust your configuration to run the Chrome browser tests.
|
||||
|
||||
There are configuration files for both the [Karma JavaScript test runner](http://karma-runner.github.io/2.0/config/configuration-file.html)
|
||||
There are configuration files for both the [Karma JavaScript test runner](https://karma-runner.github.io/latest/config/configuration-file.html)
|
||||
and [Protractor](https://www.protractortest.org/#/api-overview) end-to-end testing tool,
|
||||
which you must adjust to start Chrome without sandboxing.
|
||||
|
||||
@ -259,7 +259,7 @@ The code coverage percentages let you estimate how much of your code is tested.
|
||||
If your team decides on a set minimum amount to be unit tested, you can enforce this minimum with the Angular CLI.
|
||||
|
||||
For example, suppose you want the code base to have a minimum of 80% code coverage.
|
||||
To enable this, open the [Karma](http://karma-runner.github.io/0.13/index.html) test platform configuration file, `karma.conf.js`, and add the following in the `coverageIstanbulReporter:` key.
|
||||
To enable this, open the [Karma](https://karma-runner.github.io) test platform configuration file, `karma.conf.js`, and add the following in the `coverageIstanbulReporter:` key.
|
||||
|
||||
```
|
||||
coverageIstanbulReporter: {
|
||||
@ -1010,7 +1010,7 @@ _compiles the app before running the tests_.
|
||||
|
||||
However, if you run the tests in a **non-CLI environment**,
|
||||
tests of this component may fail.
|
||||
For example, if you run the `BannerComponent` tests in a web coding environment such as [plunker](http://plnkr.co/), you'll see a message like this one:
|
||||
For example, if you run the `BannerComponent` tests in a web coding environment such as [plunker](https://plnkr.co/), you'll see a message like this one:
|
||||
|
||||
<code-example language="sh" class="code-shell" hideCopy>
|
||||
Error: This test module uses the component BannerComponent
|
||||
@ -1489,7 +1489,7 @@ While the `async()` and `fakeAsync()` functions greatly
|
||||
simplify Angular asynchronous testing,
|
||||
you can still fall back to the traditional technique
|
||||
and pass `it` a function that takes a
|
||||
[`done` callback](http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support).
|
||||
[`done` callback](https://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support).
|
||||
|
||||
You can't call `done()` in `async()` or `fakeAsync()` functions, because the `done parameter`
|
||||
is `undefined`.
|
||||
|
@ -62,7 +62,7 @@ Your app may have to launch faster to engage these users before they decide to d
|
||||
|
||||
With Angular Universal, you can generate landing pages for the app that look like the complete app.
|
||||
The pages are pure HTML, and can display even if JavaScript is disabled.
|
||||
The pages don't handle browser events, but they _do_ support navigation through the site using `[routerLink](guide/router#router-link)`.
|
||||
The pages don't handle browser events, but they _do_ support navigation through the site using [`routerLink`](guide/router#router-link).
|
||||
|
||||
In practice, you'll serve a static version of the landing page to hold the user's attention.
|
||||
At the same time, you'll load the full Angular app behind it.
|
||||
|
135
aio/content/guide/workspace-config.md
Normal file
135
aio/content/guide/workspace-config.md
Normal file
@ -0,0 +1,135 @@
|
||||
# Angular Workspace Configuration
|
||||
|
||||
A file named `angular.json` at the root level of an Angular [workspace](guide/glossary#workspace) provides workspace-wide and project-specific configuration defaults for build and development tools provided by the Angular CLI.
|
||||
Path values given in the configuration are relative to the root workspace folder.
|
||||
|
||||
## Overall JSON structure
|
||||
|
||||
At the top level of `angular.json`, a few properties configure the workspace, and a `projects` section contains the remaining per-project configuration options.
|
||||
|
||||
* `version`: The configuration-file version.
|
||||
* `newProjectRoot`: Path where new projects are created. Absolute or relative to the workspace folder.
|
||||
* `defaultProject`: Default project name to use in commands, where not provided as an argument. When you use `ng new` to create a new app in a new workspace, that app is the default project for the workspace until you change it here.
|
||||
* `projects` : Contains a subsection for each project (library, app, e2e test app) in the workspace, with the per-project configuration options.
|
||||
|
||||
The initial app that you create with `ng new app_name` is listed under "projects", along with its corresponding end-to-end test app:
|
||||
|
||||
<code-example format="." language="none" linenums="false">
|
||||
projects
|
||||
app_name
|
||||
...
|
||||
app_name-e2e
|
||||
...
|
||||
</code-example>
|
||||
|
||||
Each additional app that you create with `ng generate application` has a corresponding end-to-end test project, with its own configuration section.
|
||||
When you create a library project with `ng generate library`, the library project is also added to the `projects` section.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Note that the `projects` section of the configuration file does not correspond exactly to the workspace file structure.
|
||||
* The initial app created by `ng new` is at the top level of the workspace file structure, along with its e2e app.
|
||||
* Additional apps, e2e apps, and libraries go into a `projects` folder in the workspace.
|
||||
|
||||
For more information, see [Workspace and project file structure](guide/file-structure).
|
||||
|
||||
</div>
|
||||
|
||||
## Project configuration options
|
||||
|
||||
The following top-level configuration properties are available for each project, under `projects:<project_name>`.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
"my-v7-app": {
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"projectType": "application",
|
||||
"prefix": "app",
|
||||
"schematics": {},
|
||||
"architect": {}
|
||||
}
|
||||
</code-example>
|
||||
|
||||
| PROPERTY | DESCRIPTION |
|
||||
| :-------------- | :---------------------------- |
|
||||
| `root` | The root folder for this project's files, relative to the workspace folder. Empty for the initial app, which resides at the top level of the workspace. |
|
||||
| `sourceRoot` | The root folder for this project's source files. |
|
||||
| `projectType` | One of "application" or "library". An application can run independently in a browser, while a library cannot. Both an app and its e2e test app are of type "application".|
|
||||
| `prefix` | A string that Angular prepends to generated selectors. Can be customized to identify an app or feature area. |
|
||||
| `schematics` | An object containing schematics that customize CLI commands for this project. |
|
||||
| `architect` | An object containing configuration defaults for Architect builder targets for this project. |
|
||||
|
||||
## Project tool configuration options
|
||||
|
||||
Architect is the tool that the CLI uses to perform complex tasks such as compilation and test running, according to provided configurations. The `architect` section contains a set of Architect *targets*. Many of the targets correspond to the CLI commands that run them. Some additional predefined targets can be run using the `ng run` command, and you can define your own targets.
|
||||
|
||||
Each target object specifies the `builder` for that target, which is the npm package for the tool that Architect runs. In addition, each target has an `options` section that configure default options for the target, and a `configurations` section that names and specifies alternative configurations for the target. See the example in [Build target](#build-target) below.
|
||||
|
||||
<code-example format="." language="json" linenums="false">
|
||||
"architect": {
|
||||
"build": { },
|
||||
"serve": { },
|
||||
"e2e" : { },
|
||||
"test": { },
|
||||
"lint": { },
|
||||
"extract-i18n": { },
|
||||
"server": { },
|
||||
"app-shell": { }
|
||||
}
|
||||
</code-example>
|
||||
|
||||
* The `architect/build` section configures defaults for options of the `ng build` command. See [Build target](#build-target) below for more information.
|
||||
|
||||
* The `architect/serve` section overrides build defaults and supplies additional serve defaults for the `ng serve` command. In addition to the options available for the `ng build` command, it adds options related to serving the app.
|
||||
|
||||
* The `architect/e2e` section overrides build-option defaults for building end-to-end testing apps using the `ng e2e` command.
|
||||
|
||||
* The `architect/test` section overrides build-option defaults for test builds and supplies additional test-running defaults for the `ng test` command.
|
||||
|
||||
* The `architect/lint` section configures defaults for options of the `ng lint` command, which performs code analysis on project source files. The default linting tool for Angular is [TSLint](https://palantir.github.io/tslint/).
|
||||
|
||||
* The `architect/extract-i18n` section configures defaults for options of the `ng-xi18n` tool used by the `ng xi18n` command, which extracts marked message strings from source code and outputs translation files.
|
||||
|
||||
* The `architect/server` section configures defaults for creating a Universal app with server-side rendering, using the `ng run <project>:server` command.
|
||||
|
||||
* The `architect/app-shell` section configures defaults for creating an app shell for a progressive web app (PWA), using the `ng run <project>:app-shell` command.
|
||||
|
||||
In general, the options for which you can configure defaults correspond to the command options listed in the [CLI reference page](cli) for each command.
|
||||
Note that all options in the configuration file must use [camelCase](guide/glossary#case-conventions), rather than dash-case.
|
||||
|
||||
{@a build-target}
|
||||
|
||||
## Build target
|
||||
|
||||
The `architect/build` section configures defaults for options of the `ng build` command. It has the following top-level properties.
|
||||
|
||||
| PROPERTY | DESCRIPTION |
|
||||
| :-------------- | :---------------------------- |
|
||||
| `builder` | The npm package for the build tool used to create this target. The default is `@angular-devkit/build-angular:browser`, which uses the [webpack](https://webpack.js.org/) package bundler. |
|
||||
| `options` | This section contains defaults for build options, used when no named alternative configuration is specified. See [Default build options](#build-props) below. |
|
||||
| `configurations`| This section defines and names alternative configurations for different intended destinations. It contains a section for each named configuration, which sets the default options for that intended environment. See [Alternate build configurations](#build-configs) below. |
|
||||
|
||||
{@a build-configs}
|
||||
|
||||
### Alternate build configurations
|
||||
|
||||
By default, a `production` configuration is defined, and the `ng build` command has `--prod` option that builds using this configuration. The `production` configuration sets defaults that optimize the app in a number of ways, such bundling files, minimizing excess whitespace, removing comments and dead code, and rewriting code to use short, cryptic names ("minification").
|
||||
|
||||
You can define and name additional alternate configurations (such as `stage`, for instance) appropriate to your development process. Some examples of different build configurations are `stable`, `archive` and `next` used by AIO itself, and the individual locale-specific configurations required for building localized versions of an app. For details, see [Internationalization (i18n)](guide/i18n#merge-aot).
|
||||
|
||||
{@a build-props}
|
||||
|
||||
### Additional build and test options
|
||||
|
||||
The configurable options for a default or targeted build generally correspond to the options available for the [`ng build`](cli/build), [`ng serve`](cli/serve), and [`ng test`](cli/test) commands. For details of those options and their possible values, see the [CLI Reference](cli).
|
||||
|
||||
Some additional options (listed below) can only be set through the configuration file, either by direct editing or with the `ng config` command.
|
||||
|
||||
| OPTIONS PROPERTIES | DESCRIPTION |
|
||||
| :------------------------- | :---------------------------- |
|
||||
| `fileReplacements` | An object containing files and their compile-time replacements. |
|
||||
| `stylePreprocessorOptions` | An object containing option-value pairs to pass to style preprocessors. |
|
||||
| `assets` | An object containing paths to static assets to add to the global context of the project. The default paths point to the project's icon file and its `assets` folder. |
|
||||
| `styles` | An object containing style files to add to the global context of the project. Angular CLI supports CSS imports and all major CSS preprocessors: [sass/scss](http://sass-lang.com/), [less](http://lesscss.org/), and [stylus](http://stylus-lang.com/). |
|
||||
| `scripts` | An object containing JavaScript script files to add to the global context of the project. The scripts are loaded exactly as if you had added them in a `<script>` tag inside `index.html`. |
|
||||
| `budgets` | Default size-budget type and threshholds for all or parts of your app. You can configure the builder to report a warning or an error when the output reaches or exceeds a threshold size. See [Configure size budgets](guide/build#configure-size-budgets). (Not available in `test` section.) |
|
BIN
aio/content/images/bios/brian-love.jpg
Normal file
BIN
aio/content/images/bios/brian-love.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 162 KiB |
BIN
aio/content/images/bios/katerina.jpg
Normal file
BIN
aio/content/images/bios/katerina.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
File diff suppressed because it is too large
Load Diff
@ -13,12 +13,6 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- AngularMix -->
|
||||
<tr>
|
||||
<th><a href="https://angularmix.com/" title="AngularMix">AngularMix</a></th>
|
||||
<td>Orlando, Florida</td>
|
||||
<td>October 10-12, 2018</td>
|
||||
</tr>
|
||||
<!-- ReactiveConf -->
|
||||
<tr>
|
||||
<th><a href="https://reactiveconf.com/" title="ReactiveConf">ReactiveConf</a></th>
|
||||
@ -44,41 +38,11 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- AngularConnect-->
|
||||
<tr>
|
||||
<th><a href="http://angularconnect.com" title="AngularConnect">AngularConnect</a></th>
|
||||
<td>London, United Kingdom</td>
|
||||
<td>November 7-8, 2017</td>
|
||||
</tr>
|
||||
<!-- ngAtlanta-->
|
||||
<tr>
|
||||
<th><a href="http://ng-atl.org/" title="ngAtlanta">ngAtlanta</a></th>
|
||||
<td>Atlanta, Georgia</td>
|
||||
<td>January 30, 2018</td>
|
||||
</tr>
|
||||
<!-- ngVikings-->
|
||||
<tr>
|
||||
<th><a href="https://ngvikings.org/" title="ngVikings">ngVikings</a></th>
|
||||
<td>Helsinki, Finland</td>
|
||||
<td>March 1-2, 2018</td>
|
||||
</tr>
|
||||
<!-- ngconf 2018-->
|
||||
<tr>
|
||||
<th><a href="https://www.ng-conf.org/" title="ng-conf">ng-conf</a></th>
|
||||
<td>Salt Lake City, Utah</td>
|
||||
<td>April 18-20, 2018</td>
|
||||
</tr>
|
||||
<!-- WeRDevs-->
|
||||
<tr>
|
||||
<th><a href="https://www.wearedevelopers.com/" title="WeAreDevs">WeAreDevelopers</a></th>
|
||||
<td>Vienna, Austria</td>
|
||||
<td>May 16-18, 2018</td>
|
||||
</tr>
|
||||
<!-- ngJapan-->
|
||||
<tr>
|
||||
<th><a href="https://ngjapan.org/en.html" title="ng-japan">ng-japan</a></th>
|
||||
<td>Tokyo, Japan</td>
|
||||
<td>Jun 16, 2018</td>
|
||||
<!-- AngularMix -->
|
||||
<tr>
|
||||
<th><a href="https://angularmix.com/" title="AngularMix">AngularMix</a></th>
|
||||
<td>Orlando, Florida</td>
|
||||
<td>October 10-12, 2018</td>
|
||||
</tr>
|
||||
<!-- Angular Conf Australia-->
|
||||
<tr>
|
||||
@ -86,6 +50,36 @@
|
||||
<td>Melbourne, Australia</td>
|
||||
<td>Jun 22, 2018</td>
|
||||
</tr>
|
||||
<!-- ngJapan-->
|
||||
<tr>
|
||||
<th><a href="https://ngjapan.org/en.html" title="ng-japan">ng-japan</a></th>
|
||||
<td>Tokyo, Japan</td>
|
||||
<td>Jun 16, 2018</td>
|
||||
</tr>
|
||||
<!-- WeRDevs-->
|
||||
<tr>
|
||||
<th><a href="https://www.wearedevelopers.com/" title="WeAreDevs">WeAreDevelopers</a></th>
|
||||
<td>Vienna, Austria</td>
|
||||
<td>May 16-18, 2018</td>
|
||||
</tr>
|
||||
<!-- ngconf 2018-->
|
||||
<tr>
|
||||
<th><a href="https://www.ng-conf.org/" title="ng-conf">ng-conf</a></th>
|
||||
<td>Salt Lake City, Utah</td>
|
||||
<td>April 18-20, 2018</td>
|
||||
</tr>
|
||||
<!-- ngVikings-->
|
||||
<tr>
|
||||
<th><a href="https://ngvikings.org/" title="ngVikings">ngVikings</a></th>
|
||||
<td>Helsinki, Finland</td>
|
||||
<td>March 1-2, 2018</td>
|
||||
</tr>
|
||||
<!-- ngAtlanta-->
|
||||
<tr>
|
||||
<th><a href="http://ng-atl.org/" title="ngAtlanta">ngAtlanta</a></th>
|
||||
<td>Atlanta, Georgia</td>
|
||||
<td>January 30, 2018</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</article>
|
||||
|
@ -22,6 +22,12 @@
|
||||
"rev": true,
|
||||
"title": "Made with Angular",
|
||||
"url": "https://www.madewithangular.com/"
|
||||
},
|
||||
"angular-subreddit": {
|
||||
"desc": "An Angular-dedicated subreddit.",
|
||||
"rev": true,
|
||||
"title": "Angular Subreddit",
|
||||
"url": "https://www.reddit.com/r/Angular2/"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -149,6 +155,13 @@
|
||||
"rev": true,
|
||||
"title": "AngularCommerce",
|
||||
"url": "https://github.com/NodeArt/angular-commerce"
|
||||
},
|
||||
"ngx-api-utils": {
|
||||
"desc": "ngx-api-utils is a lean library of utilities and helpers to quickly integrate any HTTP API (REST, Ajax, and any other) with Angular.",
|
||||
"logo": "",
|
||||
"rev": true,
|
||||
"title": "ngx-api-utils",
|
||||
"url": "https://github.com/ngx-api-utils/ngx-api-utils"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -211,7 +224,7 @@
|
||||
"logo": "https://cloud.githubusercontent.com/assets/1016365/10639063/138338bc-7806-11e5-8057-d34c75f3cafc.png",
|
||||
"rev": true,
|
||||
"title": "Angular Universal",
|
||||
"url": "https://github.com/angular/universal"
|
||||
"url": "https://angular.io/guide/universal"
|
||||
},
|
||||
"c1": {
|
||||
"desc": "Lightweight development only Node.js® server",
|
||||
@ -273,6 +286,13 @@
|
||||
"rev": true,
|
||||
"title": "UI-jar - Test Driven Style Guide Development",
|
||||
"url": "https://github.com/ui-jar/ui-jar"
|
||||
},
|
||||
"protactor": {
|
||||
"desc": "The official end to end testing framework for Angular apps",
|
||||
"logo": "",
|
||||
"rev": true,
|
||||
"title": "Protractor",
|
||||
"url": "https://protractor.angular.io/"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -362,7 +382,7 @@
|
||||
"logo": "",
|
||||
"rev": true,
|
||||
"title": "Angular Material",
|
||||
"url": "https://github.com/angular/material2"
|
||||
"url": "https://material.angular.io/"
|
||||
},
|
||||
"mcc": {
|
||||
"desc": "Material components made by the community",
|
||||
@ -377,6 +397,12 @@
|
||||
"title": "Ant Design of Angular (ng-zorro-antd)",
|
||||
"url": "https://ng.ant.design/docs/introduce/en"
|
||||
},
|
||||
"ngzorromobile": {
|
||||
"desc": "A set of enterprise-class mobile UI components based on Ant Design Mobile and Angular",
|
||||
"rev": true,
|
||||
"title": "Ant Design Mobile of Angular (ng-zorro-antd-mobile)",
|
||||
"url": "http://ng.mobile.ant.design/#/docs/introduce/en"
|
||||
},
|
||||
"aggrid": {
|
||||
"desc": "A datagrid for Angular with enterprise style features such as sorting, filtering, custom rendering, editing, grouping, aggregation and pivoting.",
|
||||
"rev": true,
|
||||
|
@ -120,3 +120,20 @@ Try this <live-example></live-example>.
|
||||
<live-example embedded name="testy" stackblitz="super-stackblitz"></live-example>
|
||||
|
||||
<p>More text follows ...</p>
|
||||
|
||||
<p>Getting Started Widgets</p>
|
||||
|
||||
<p>Interpolation</p>
|
||||
<aio-gs-interpolation></aio-gs-interpolation>
|
||||
|
||||
<p>Property Binding</p>
|
||||
<aio-gs-property-binding></aio-gs-property-binding>
|
||||
|
||||
<p>Event Binding</p>
|
||||
<aio-gs-event-binding></aio-gs-event-binding>
|
||||
|
||||
<p>NgIf</p>
|
||||
<aio-gs-ng-if></aio-gs-ng-if>
|
||||
|
||||
<p>NgFor</p>
|
||||
<aio-gs-ng-for></aio-gs-ng-for>
|
||||
|
@ -513,12 +513,18 @@
|
||||
{
|
||||
"url": "guide/file-structure",
|
||||
"title": "Project File Structure",
|
||||
"tooltip": "How your Angular workspace looks in your filesystem."
|
||||
"tooltip": "How your Angular workspace looks on your filesystem."
|
||||
},
|
||||
{
|
||||
"url": "guide/workspace-config",
|
||||
"title": "Workspace Configuration",
|
||||
"tooltip": "The \"angular.json\" file contains workspace and project configuration defaults for Angular CLI commands."
|
||||
},
|
||||
|
||||
{
|
||||
"url": "guide/npm-packages",
|
||||
"title": "Packages",
|
||||
"tooltip": "Explanation of npm packages installed into a project by default."
|
||||
"title": "npm Dependencies",
|
||||
"tooltip": "Description of npm packages required at development time and at runtime."
|
||||
},
|
||||
{
|
||||
"url": "guide/typescript-configuration",
|
||||
@ -576,31 +582,15 @@
|
||||
"title": "Release Information",
|
||||
"tooltip": "Angular release practices, updating, and upgrading.",
|
||||
"children": [
|
||||
{
|
||||
"url": "guide/updating",
|
||||
"title": "Keeping Up-to-Date",
|
||||
"tooltip": "Information about updating Angular applications and libraries to the latest version."
|
||||
},
|
||||
{
|
||||
"url": "guide/releases",
|
||||
"title": "Angular Releases",
|
||||
"tooltip": "Angular versioning, release, support, and deprecation policies and practices."
|
||||
},
|
||||
{
|
||||
"url": "guide/updating",
|
||||
"title": "Keeping Up-to-Date",
|
||||
"tooltip": "Information about updating Angular applications and libraries to the latest version."
|
||||
},
|
||||
{
|
||||
"title": "Upgrading from AngularJS",
|
||||
"tooltip": "Incrementally upgrade an AngularJS application to Angular.",
|
||||
"children": [
|
||||
{
|
||||
"url": "guide/upgrade",
|
||||
"title": "Upgrading Instructions",
|
||||
"tooltip": "Incrementally upgrade an AngularJS application to Angular."
|
||||
},
|
||||
{
|
||||
"url": "guide/ajs-quick-reference",
|
||||
"title": "AngularJS-Angular Concepts",
|
||||
"tooltip": "Learn how AngularJS concepts and techniques map to Angular."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -748,6 +738,7 @@
|
||||
],
|
||||
|
||||
"docVersions": [
|
||||
{ "title": "v6", "url": "https://v6.angular.io" },
|
||||
{ "title": "v5", "url": "https://v5.angular.io" },
|
||||
{ "title": "v4", "url": "https://v4.angular.io" },
|
||||
{ "title": "v2", "url": "https://v2.angular.io" },
|
||||
|
@ -19,7 +19,7 @@ To set up your development environment, follow these instructions in [Getting St
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Note:**: You do not need to complete the entire Getting Started. After you complete the above two sections of Getting Started, your environment is set up. Continue below to create the Tour of Heroes workspace and an initial app project.
|
||||
**Note:** You do not need to complete the entire Getting Started. After you complete the above two sections of Getting Started, your environment is set up. Continue below to create the Tour of Heroes workspace and an initial app project.
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -77,8 +77,13 @@ _after importing the `HttpClientModule`_,
|
||||
The `forRoot()` configuration method takes an `InMemoryDataService` class
|
||||
that primes the in-memory database.
|
||||
|
||||
The _Tour of Heroes_ sample creates such a class
|
||||
`src/app/in-memory-data.service.ts` which has the following content:
|
||||
The class `src/app/in-memory-data.service.ts` is generated by the following command:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng generate service InMemoryData
|
||||
</code-example>
|
||||
|
||||
This class has the following content:
|
||||
|
||||
<code-example path="toh-pt6/src/app/in-memory-data.service.ts" region="init" header="src/app/in-memory-data.service.ts" linenums="false"></code-example>
|
||||
|
||||
@ -461,7 +466,7 @@ Replace the generated `HeroSearchComponent` _template_ with a text box and a lis
|
||||
Add private CSS styles to `hero-search.component.css`
|
||||
as listed in the [final code review](#herosearchcomponent) below.
|
||||
|
||||
As the user types in the search box, a *keyup* event binding calls the component's `search()`
|
||||
As the user types in the search box, an *input* event binding calls the component's `search()`
|
||||
method with the new search box value.
|
||||
|
||||
{@a asyncpipe}
|
||||
@ -511,7 +516,7 @@ You can also push values into that `Observable` by calling its `next(value)` met
|
||||
as the `search()` method does.
|
||||
|
||||
The `search()` method is called via an _event binding_ to the
|
||||
textbox's `keystroke` event.
|
||||
textbox's `input` event.
|
||||
|
||||
<code-example path="toh-pt6/src/app/hero-search/hero-search.component.html" region="input"></code-example>
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
"build-for": "yarn ~~build --configuration",
|
||||
"prebuild-local": "yarn setup-local",
|
||||
"build-local": "yarn ~~build --configuration=stable",
|
||||
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js a2129510d7d57d1c02bec563872adf0204e11a2f",
|
||||
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js b50950b97",
|
||||
"lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint",
|
||||
"test": "yarn check-env && ng test",
|
||||
"pree2e": "yarn check-env && yarn update-webdriver",
|
||||
@ -30,6 +30,8 @@
|
||||
"setup-local": "yarn aio-use-local && yarn example-use-local",
|
||||
"postsetup-local": "yarn postsetup",
|
||||
"set-opensearch-url": "node --eval \"const sh = require('shelljs'); sh.set('-e'); sh.sed('-i', /PLACEHOLDER_URL/g, process.argv[1], 'dist/assets/opensearch.xml');\"",
|
||||
"presmoke-tests": "yarn update-webdriver",
|
||||
"smoke-tests": "protractor tests/deployment/e2e/protractor.conf.js --suite smoke --baseUrl",
|
||||
"test-pwa-score": "node scripts/test-pwa-score",
|
||||
"test-pwa-score-localhost": "run-p --race \"~~http-server dist -p 4200 --silent\" \"test-pwa-score http://localhost:4200 {1} {2}\" --",
|
||||
"example-e2e": "yarn example-check-local && node ./tools/examples/run-example-e2e",
|
||||
@ -73,17 +75,17 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^7.0.0-rc.1",
|
||||
"@angular/cdk": "7.0.0-rc.1",
|
||||
"@angular/common": "^7.0.0-rc.1",
|
||||
"@angular/core": "^7.0.0-rc.1",
|
||||
"@angular/elements": "^7.0.0-rc.1",
|
||||
"@angular/forms": "^7.0.0-rc.1",
|
||||
"@angular/material": "7.0.0-rc.1",
|
||||
"@angular/platform-browser": "^7.0.0-rc.1",
|
||||
"@angular/platform-browser-dynamic": "^7.0.0-rc.1",
|
||||
"@angular/router": "^7.0.0-rc.1",
|
||||
"@angular/service-worker": "^7.0.0-rc.1",
|
||||
"@angular/animations": "^7.0.0",
|
||||
"@angular/cdk": "7.0.0",
|
||||
"@angular/common": "^7.0.0",
|
||||
"@angular/core": "^7.0.0",
|
||||
"@angular/elements": "^7.0.0",
|
||||
"@angular/forms": "^7.0.0",
|
||||
"@angular/material": "7.0.0",
|
||||
"@angular/platform-browser": "^7.0.0",
|
||||
"@angular/platform-browser-dynamic": "^7.0.0",
|
||||
"@angular/router": "^7.0.0",
|
||||
"@angular/service-worker": "^7.0.0",
|
||||
"@webcomponents/custom-elements": "^1.2.0",
|
||||
"classlist.js": "^1.1.20150312",
|
||||
"core-js": "^2.4.1",
|
||||
@ -93,27 +95,27 @@
|
||||
"zone.js": "^0.8.26"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.9.0-rc.1",
|
||||
"@angular/cli": "^7.0.0-rc.2",
|
||||
"@angular/compiler": "^7.0.0-rc.1",
|
||||
"@angular/compiler-cli": "^7.0.0-rc.1",
|
||||
"@angular/language-service": "^7.0.0-rc.1",
|
||||
"@angular-devkit/build-angular": "~0.10.0",
|
||||
"@angular/cli": "^7.0.1",
|
||||
"@angular/compiler": "^7.0.0",
|
||||
"@angular/compiler-cli": "^7.0.0",
|
||||
"@angular/language-service": "^7.0.0",
|
||||
"@types/jasmine": "^2.5.52",
|
||||
"@types/jasminewd2": "^2.0.4",
|
||||
"@types/node": "~6.0.60",
|
||||
"archiver": "^1.3.0",
|
||||
"canonical-path": "^0.0.2",
|
||||
"canonical-path": "1.0.0",
|
||||
"chalk": "^2.1.0",
|
||||
"cjson": "^0.5.0",
|
||||
"codelyzer": "~4.2.1",
|
||||
"cross-spawn": "^5.1.0",
|
||||
"css-selector-parser": "^1.3.0",
|
||||
"dgeni": "^0.4.7",
|
||||
"dgeni-packages": "^0.26.9",
|
||||
"dgeni-packages": "^0.26.12",
|
||||
"entities": "^1.1.1",
|
||||
"eslint": "^3.19.0",
|
||||
"eslint-plugin-jasmine": "^2.2.0",
|
||||
"firebase-tools": "^3.2.1",
|
||||
"firebase-tools": "^5.1.1",
|
||||
"fs-extra": "^2.1.2",
|
||||
"globby": "^6.1.0",
|
||||
"hast-util-is-element": "^1.0.0",
|
||||
@ -151,7 +153,7 @@
|
||||
"tree-kill": "^1.1.0",
|
||||
"ts-node": "^3.3.0",
|
||||
"tslint": "~5.9.1",
|
||||
"typescript": "^3.1.2",
|
||||
"typescript": "^3.1.3",
|
||||
"uglify-js": "^3.0.15",
|
||||
"unist-util-filter": "^0.2.1",
|
||||
"unist-util-source": "^1.0.1",
|
||||
|
@ -2,8 +2,8 @@
|
||||
"aio": {
|
||||
"master": {
|
||||
"uncompressed": {
|
||||
"runtime": 3173,
|
||||
"main": 494475,
|
||||
"runtime": 3881,
|
||||
"main": 499953,
|
||||
"polyfills": 53926,
|
||||
"prettify": 14917
|
||||
}
|
||||
|
@ -2,24 +2,23 @@
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
source "`dirname $0`/../../scripts/ci/env.sh" print
|
||||
|
||||
readonly INPUT_DIR=dist/
|
||||
readonly OUTPUT_FILE=$PROJECT_ROOT/$1
|
||||
readonly PR_NUMBER=$2
|
||||
readonly PR_LAST_SHA=$3
|
||||
readonly deployedUrl=https://pr${PR_NUMBER}-${PR_LAST_SHA:0:7}.ngbuilds.io/
|
||||
readonly relativeOutputPath=$1
|
||||
readonly prNumber=$2
|
||||
readonly prLastSha=$3
|
||||
readonly inputDir=dist/
|
||||
readonly outputFile=$PROJECT_ROOT/$relativeOutputPath
|
||||
readonly deployedUrl=https://pr${prNumber}-${prLastSha:0:7}.ngbuilds.io/
|
||||
|
||||
(
|
||||
cd $PROJECT_ROOT/aio
|
||||
|
||||
# Build and store the app
|
||||
yarn build
|
||||
yarn build --progress=false
|
||||
|
||||
# Set deployedUrl as parameter in the opensearch description
|
||||
# deployedUrl must end with /
|
||||
yarn set-opensearch-url $deployedUrl
|
||||
|
||||
mkdir -p "`dirname $OUTPUT_FILE`"
|
||||
tar --create --gzip --directory "$INPUT_DIR" --file "$OUTPUT_FILE" .
|
||||
mkdir -p "`dirname $outputFile`"
|
||||
tar --create --gzip --directory "$inputDir" --file "$outputFile" .
|
||||
)
|
||||
|
@ -1,35 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# WARNING: FIREBASE_TOKEN should NOT be printed.
|
||||
# WARNING: CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN should NOT be printed.
|
||||
set +x -eu -o pipefail
|
||||
|
||||
# Only deploy if this not a PR. PRs are deployed early in `build.sh`.
|
||||
if [[ $TRAVIS_PULL_REQUEST != "false" ]]; then
|
||||
# Do not deploy if we are running in a fork.
|
||||
if [[ "$CI_REPO_OWNER/$CI_REPO_NAME" != "angular/angular" ]]; then
|
||||
echo "Skipping deploy because this is not angular/angular."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Do not deploy if this is a PR. PRs are deployed in the `aio_preview` CircleCI job.
|
||||
if [[ $CI_PULL_REQUEST != "false" ]]; then
|
||||
echo "Skipping deploy because this is a PR build."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Do not deploy if the current commit is not the latest on its branch.
|
||||
readonly LATEST_COMMIT=$(git ls-remote origin $TRAVIS_BRANCH | cut -c1-40)
|
||||
if [[ $TRAVIS_COMMIT != $LATEST_COMMIT ]]; then
|
||||
echo "Skipping deploy because $TRAVIS_COMMIT is not the latest commit ($LATEST_COMMIT)."
|
||||
readonly latestCommit=$(git ls-remote origin $CI_BRANCH | cut -c1-40)
|
||||
if [[ $CI_COMMIT != $latestCommit ]]; then
|
||||
echo "Skipping deploy because $CI_COMMIT is not the latest commit ($latestCommit)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# The deployment mode is computed based on the branch we are building
|
||||
if [[ $TRAVIS_BRANCH == master ]]; then
|
||||
if [[ $CI_BRANCH == master ]]; then
|
||||
readonly deployEnv=next
|
||||
elif [[ $TRAVIS_BRANCH == $STABLE_BRANCH ]]; then
|
||||
elif [[ $CI_BRANCH == $CI_STABLE_BRANCH ]]; then
|
||||
readonly deployEnv=stable
|
||||
else
|
||||
# Extract the major versions from the branches, e.g. the 4 from 4.3.x
|
||||
readonly majorVersion=${TRAVIS_BRANCH%%.*}
|
||||
readonly majorVersionStable=${STABLE_BRANCH%%.*}
|
||||
readonly majorVersion=${CI_BRANCH%%.*}
|
||||
readonly majorVersionStable=${CI_STABLE_BRANCH%%.*}
|
||||
|
||||
# Do not deploy if the major version is not less than the stable branch major version
|
||||
if [[ !( "$majorVersion" < "$majorVersionStable" ) ]]; then
|
||||
echo "Skipping deploy of branch \"${TRAVIS_BRANCH}\" to firebase."
|
||||
echo "We only deploy archive branches with the major version less than the stable branch: \"${STABLE_BRANCH}\""
|
||||
echo "Skipping deploy of branch \"$CI_BRANCH\" to firebase."
|
||||
echo "We only deploy archive branches with the major version less than the stable branch: \"$CI_STABLE_BRANCH\""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@ -46,9 +52,9 @@ else
|
||||
)
|
||||
|
||||
# Do not deploy as it is not the latest branch for the given major version
|
||||
if [[ $TRAVIS_BRANCH != $mostRecentMinorVersion ]]; then
|
||||
echo "Skipping deploy of branch \"${TRAVIS_BRANCH}\" to firebase."
|
||||
echo "There is a more recent branch with the same major version: \"${mostRecentMinorVersion}\""
|
||||
if [[ $CI_BRANCH != $mostRecentMinorVersion ]]; then
|
||||
echo "Skipping deploy of branch \"$CI_BRANCH\" to firebase."
|
||||
echo "There is a more recent branch with the same major version: \"$mostRecentMinorVersion\""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@ -59,21 +65,21 @@ case $deployEnv in
|
||||
next)
|
||||
readonly projectId=aio-staging
|
||||
readonly deployedUrl=https://next.angular.io/
|
||||
readonly firebaseToken=$FIREBASE_TOKEN
|
||||
readonly firebaseToken=$CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN
|
||||
;;
|
||||
stable)
|
||||
readonly projectId=angular-io
|
||||
readonly deployedUrl=https://angular.io/
|
||||
readonly firebaseToken=$FIREBASE_TOKEN
|
||||
readonly firebaseToken=$CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN
|
||||
;;
|
||||
archive)
|
||||
readonly projectId=v${majorVersion}-angular-io
|
||||
readonly deployedUrl=https://v${majorVersion}.angular.io/
|
||||
readonly firebaseToken=$FIREBASE_TOKEN
|
||||
readonly firebaseToken=$CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Git branch : $TRAVIS_BRANCH"
|
||||
echo "Git branch : $CI_BRANCH"
|
||||
echo "Build/deploy mode : $deployEnv"
|
||||
echo "Firebase project : $projectId"
|
||||
echo "Deployment URL : $deployedUrl"
|
||||
@ -87,7 +93,7 @@ fi
|
||||
cd "`dirname $0`/.."
|
||||
|
||||
# Build the app
|
||||
yarn build-for $deployEnv
|
||||
yarn build-for $deployEnv --progress=false
|
||||
|
||||
# Include any mode-specific files
|
||||
cp -rf src/extra-files/$deployEnv/. dist/
|
||||
@ -100,9 +106,9 @@ fi
|
||||
yarn payload-size
|
||||
|
||||
# Deploy to Firebase
|
||||
firebase use "$projectId" --token "$firebaseToken"
|
||||
firebase deploy --message "Commit: $TRAVIS_COMMIT" --non-interactive --token "$firebaseToken"
|
||||
yarn firebase use "$projectId" --token "$firebaseToken"
|
||||
yarn firebase deploy --message "Commit: $CI_COMMIT" --non-interactive --token "$firebaseToken"
|
||||
|
||||
# Run PWA-score tests
|
||||
yarn test-pwa-score "$deployedUrl" "$AIO_MIN_PWA_SCORE"
|
||||
yarn test-pwa-score "$deployedUrl" "$CI_AIO_MIN_PWA_SCORE"
|
||||
)
|
||||
|
@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set +x -eu -o pipefail
|
||||
|
||||
readonly deployToFirebaseDryRun="`dirname $0`/deploy-to-firebase.sh --dry-run"
|
||||
|
||||
function check {
|
||||
if [[ $1 == $2 ]]; then
|
||||
echo Pass
|
||||
@ -14,11 +16,38 @@ function check {
|
||||
exit 1
|
||||
}
|
||||
|
||||
(
|
||||
echo ===== master - skip deploy - not angular
|
||||
actual=$(
|
||||
export BASH_ENV=/dev/null
|
||||
export CI_REPO_OWNER=angular
|
||||
export CI_REPO_NAME=notangular
|
||||
$deployToFirebaseDryRun
|
||||
)
|
||||
expected="Skipping deploy because this is not angular/angular."
|
||||
check "$actual" "$expected"
|
||||
)
|
||||
|
||||
(
|
||||
echo ===== master - skip deploy - angular fork
|
||||
actual=$(
|
||||
export BASH_ENV=/dev/null
|
||||
export CI_REPO_OWNER=notangular
|
||||
export CI_REPO_NAME=angular
|
||||
$deployToFirebaseDryRun
|
||||
)
|
||||
expected="Skipping deploy because this is not angular/angular."
|
||||
check "$actual" "$expected"
|
||||
)
|
||||
|
||||
(
|
||||
echo ===== master - skip deploy - pull request
|
||||
actual=$(
|
||||
export TRAVIS_PULL_REQUEST=true
|
||||
`dirname $0`/deploy-to-firebase.sh --dry-run
|
||||
export BASH_ENV=/dev/null
|
||||
export CI_REPO_OWNER=angular
|
||||
export CI_REPO_NAME=angular
|
||||
export CI_PULL_REQUEST=true
|
||||
$deployToFirebaseDryRun
|
||||
)
|
||||
expected="Skipping deploy because this is a PR build."
|
||||
check "$actual" "$expected"
|
||||
@ -27,11 +56,14 @@ function check {
|
||||
(
|
||||
echo ===== master - deploy success
|
||||
actual=$(
|
||||
export TRAVIS_PULL_REQUEST=false
|
||||
export TRAVIS_BRANCH=master
|
||||
export TRAVIS_COMMIT=$(git ls-remote origin master | cut -c-40)
|
||||
export FIREBASE_TOKEN=XXXXX
|
||||
`dirname $0`/deploy-to-firebase.sh --dry-run
|
||||
export BASH_ENV=/dev/null
|
||||
export CI_REPO_OWNER=angular
|
||||
export CI_REPO_NAME=angular
|
||||
export CI_PULL_REQUEST=false
|
||||
export CI_BRANCH=master
|
||||
export CI_COMMIT=$(git ls-remote origin master | cut -c1-40)
|
||||
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
|
||||
$deployToFirebaseDryRun
|
||||
)
|
||||
expected="Git branch : master
|
||||
Build/deploy mode : next
|
||||
@ -43,10 +75,13 @@ Deployment URL : https://next.angular.io/"
|
||||
(
|
||||
echo ===== master - skip deploy - commit not HEAD
|
||||
actual=$(
|
||||
export TRAVIS_PULL_REQUEST=false
|
||||
export TRAVIS_BRANCH=master
|
||||
export TRAVIS_COMMIT=DUMMY_TEST_COMMIT
|
||||
`dirname $0`/deploy-to-firebase.sh --dry-run
|
||||
export BASH_ENV=/dev/null
|
||||
export CI_REPO_OWNER=angular
|
||||
export CI_REPO_NAME=angular
|
||||
export CI_PULL_REQUEST=false
|
||||
export CI_BRANCH=master
|
||||
export CI_COMMIT=DUMMY_TEST_COMMIT
|
||||
$deployToFirebaseDryRun
|
||||
)
|
||||
expected="Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ($(git ls-remote origin master | cut -c1-40))."
|
||||
check "$actual" "$expected"
|
||||
@ -55,12 +90,15 @@ Deployment URL : https://next.angular.io/"
|
||||
(
|
||||
echo ===== stable - deploy success
|
||||
actual=$(
|
||||
export TRAVIS_PULL_REQUEST=false
|
||||
export TRAVIS_BRANCH=4.3.x
|
||||
export STABLE_BRANCH=4.3.x
|
||||
export TRAVIS_COMMIT=$(git ls-remote origin 4.3.x | cut -c-40)
|
||||
export FIREBASE_TOKEN=XXXXX
|
||||
`dirname $0`/deploy-to-firebase.sh --dry-run
|
||||
export BASH_ENV=/dev/null
|
||||
export CI_REPO_OWNER=angular
|
||||
export CI_REPO_NAME=angular
|
||||
export CI_PULL_REQUEST=false
|
||||
export CI_BRANCH=4.3.x
|
||||
export CI_STABLE_BRANCH=4.3.x
|
||||
export CI_COMMIT=$(git ls-remote origin 4.3.x | cut -c1-40)
|
||||
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
|
||||
$deployToFirebaseDryRun
|
||||
)
|
||||
expected="Git branch : 4.3.x
|
||||
Build/deploy mode : stable
|
||||
@ -72,11 +110,14 @@ Deployment URL : https://angular.io/"
|
||||
(
|
||||
echo ===== stable - skip deploy - commit not HEAD
|
||||
actual=$(
|
||||
export TRAVIS_PULL_REQUEST=false
|
||||
export TRAVIS_BRANCH=4.3.x
|
||||
export STABLE_BRANCH=4.3.x
|
||||
export TRAVIS_COMMIT=DUMMY_TEST_COMMIT
|
||||
`dirname $0`/deploy-to-firebase.sh --dry-run
|
||||
export BASH_ENV=/dev/null
|
||||
export CI_REPO_OWNER=angular
|
||||
export CI_REPO_NAME=angular
|
||||
export CI_PULL_REQUEST=false
|
||||
export CI_BRANCH=4.3.x
|
||||
export CI_STABLE_BRANCH=4.3.x
|
||||
export CI_COMMIT=DUMMY_TEST_COMMIT
|
||||
$deployToFirebaseDryRun
|
||||
)
|
||||
expected="Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ($(git ls-remote origin 4.3.x | cut -c1-40))."
|
||||
check "$actual" "$expected"
|
||||
@ -85,12 +126,15 @@ Deployment URL : https://angular.io/"
|
||||
(
|
||||
echo ===== archive - deploy success
|
||||
actual=$(
|
||||
export TRAVIS_PULL_REQUEST=false
|
||||
export TRAVIS_BRANCH=2.4.x
|
||||
export STABLE_BRANCH=4.3.x
|
||||
export TRAVIS_COMMIT=$(git ls-remote origin 2.4.x | cut -c-40)
|
||||
export FIREBASE_TOKEN=XXXXX
|
||||
`dirname $0`/deploy-to-firebase.sh --dry-run
|
||||
export BASH_ENV=/dev/null
|
||||
export CI_REPO_OWNER=angular
|
||||
export CI_REPO_NAME=angular
|
||||
export CI_PULL_REQUEST=false
|
||||
export CI_BRANCH=2.4.x
|
||||
export CI_STABLE_BRANCH=4.3.x
|
||||
export CI_COMMIT=$(git ls-remote origin 2.4.x | cut -c1-40)
|
||||
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
|
||||
$deployToFirebaseDryRun
|
||||
)
|
||||
expected="Git branch : 2.4.x
|
||||
Build/deploy mode : archive
|
||||
@ -102,12 +146,15 @@ Deployment URL : https://v2.angular.io/"
|
||||
(
|
||||
echo ===== archive - skip deploy - commit not HEAD
|
||||
actual=$(
|
||||
export TRAVIS_PULL_REQUEST=false
|
||||
export TRAVIS_BRANCH=2.4.x
|
||||
export STABLE_BRANCH=4.3.x
|
||||
export TRAVIS_COMMIT=DUMMY_TEST_COMMIT
|
||||
export FIREBASE_TOKEN=XXXXX
|
||||
`dirname $0`/deploy-to-firebase.sh --dry-run
|
||||
export BASH_ENV=/dev/null
|
||||
export CI_REPO_OWNER=angular
|
||||
export CI_REPO_NAME=angular
|
||||
export CI_PULL_REQUEST=false
|
||||
export CI_BRANCH=2.4.x
|
||||
export CI_STABLE_BRANCH=4.3.x
|
||||
export CI_COMMIT=DUMMY_TEST_COMMIT
|
||||
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
|
||||
$deployToFirebaseDryRun
|
||||
)
|
||||
expected="Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ($(git ls-remote origin 2.4.x | cut -c1-40))."
|
||||
check "$actual" "$expected"
|
||||
@ -116,12 +163,15 @@ Deployment URL : https://v2.angular.io/"
|
||||
(
|
||||
echo ===== archive - skip deploy - major version too high, lower minor
|
||||
actual=$(
|
||||
export TRAVIS_PULL_REQUEST=false
|
||||
export TRAVIS_BRANCH=2.1.x
|
||||
export STABLE_BRANCH=2.2.x
|
||||
export TRAVIS_COMMIT=$(git ls-remote origin 2.1.x | cut -c-40)
|
||||
export FIREBASE_TOKEN=XXXXX
|
||||
`dirname $0`/deploy-to-firebase.sh --dry-run
|
||||
export BASH_ENV=/dev/null
|
||||
export CI_REPO_OWNER=angular
|
||||
export CI_REPO_NAME=angular
|
||||
export CI_PULL_REQUEST=false
|
||||
export CI_BRANCH=2.1.x
|
||||
export CI_STABLE_BRANCH=2.2.x
|
||||
export CI_COMMIT=$(git ls-remote origin 2.1.x | cut -c-40)
|
||||
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
|
||||
$deployToFirebaseDryRun
|
||||
)
|
||||
expected="Skipping deploy of branch \"2.1.x\" to firebase.
|
||||
We only deploy archive branches with the major version less than the stable branch: \"2.2.x\""
|
||||
@ -131,12 +181,15 @@ We only deploy archive branches with the major version less than the stable bran
|
||||
(
|
||||
echo ===== archive - skip deploy - major version too high, higher minor
|
||||
actual=$(
|
||||
export TRAVIS_PULL_REQUEST=false
|
||||
export TRAVIS_BRANCH=2.4.x
|
||||
export STABLE_BRANCH=2.2.x
|
||||
export TRAVIS_COMMIT=$(git ls-remote origin 2.4.x | cut -c-40)
|
||||
export FIREBASE_TOKEN=XXXXX
|
||||
`dirname $0`/deploy-to-firebase.sh --dry-run
|
||||
export BASH_ENV=/dev/null
|
||||
export CI_REPO_OWNER=angular
|
||||
export CI_REPO_NAME=angular
|
||||
export CI_PULL_REQUEST=false
|
||||
export CI_BRANCH=2.4.x
|
||||
export CI_STABLE_BRANCH=2.2.x
|
||||
export CI_COMMIT=$(git ls-remote origin 2.4.x | cut -c-40)
|
||||
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
|
||||
$deployToFirebaseDryRun
|
||||
)
|
||||
expected="Skipping deploy of branch \"2.4.x\" to firebase.
|
||||
We only deploy archive branches with the major version less than the stable branch: \"2.2.x\""
|
||||
@ -146,12 +199,15 @@ We only deploy archive branches with the major version less than the stable bran
|
||||
(
|
||||
echo ===== archive - skip deploy - minor version too low
|
||||
actual=$(
|
||||
export TRAVIS_PULL_REQUEST=false
|
||||
export TRAVIS_BRANCH=2.1.x
|
||||
export STABLE_BRANCH=4.3.x
|
||||
export TRAVIS_COMMIT=$(git ls-remote origin 2.1.x | cut -c-40)
|
||||
export FIREBASE_TOKEN=XXXXX
|
||||
`dirname $0`/deploy-to-firebase.sh --dry-run
|
||||
export BASH_ENV=/dev/null
|
||||
export CI_REPO_OWNER=angular
|
||||
export CI_REPO_NAME=angular
|
||||
export CI_PULL_REQUEST=false
|
||||
export CI_BRANCH=2.1.x
|
||||
export CI_STABLE_BRANCH=4.3.x
|
||||
export CI_COMMIT=$(git ls-remote origin 2.1.x | cut -c-40)
|
||||
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
|
||||
$deployToFirebaseDryRun
|
||||
)
|
||||
expected="Skipping deploy of branch \"2.1.x\" to firebase.
|
||||
There is a more recent branch with the same major version: \"2.4.x\""
|
||||
|
@ -45,8 +45,9 @@ get(previewabilityCheckUrl).
|
||||
const totalSecs = Math.round((previewCheckInterval * previewCheckAttempts) / 1000);
|
||||
throw new Error(`Preview still not available after ${totalSecs}s.`);
|
||||
}).
|
||||
// The preview is now available. Run the PWA tests.
|
||||
then(() => runPwaTests());
|
||||
// The preview is now available. Run the tests.
|
||||
then(() => yarnRun('smoke-tests', previewUrl)).
|
||||
then(() => yarnRun('test-pwa-score', previewUrl, minPwaScore));
|
||||
}).
|
||||
catch(onError);
|
||||
|
||||
@ -93,15 +94,6 @@ function reportNoPreview(reason) {
|
||||
console.log(`No (public) preview available. (Reason: ${reason})`);
|
||||
}
|
||||
|
||||
function runPwaTests() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const spawnOptions = {cwd: __dirname, stdio: 'inherit'};
|
||||
spawn('yarn', ['test-pwa-score', previewUrl, minPwaScore], spawnOptions).
|
||||
on('error', reject).
|
||||
on('exit', code => (code === 0 ? resolve : reject)());
|
||||
});
|
||||
}
|
||||
|
||||
function validateArgs(args) {
|
||||
if (args.length !== 3) {
|
||||
const relativeScriptPath = relative('.', __filename.replace(/\.js$/, ''));
|
||||
@ -119,3 +111,12 @@ function wait(delay) {
|
||||
console.log(`Waiting ${delay}ms...`);
|
||||
return new Promise(resolve => setTimeout(resolve, delay));
|
||||
}
|
||||
|
||||
function yarnRun(script, ...args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const spawnOptions = {cwd: __dirname, stdio: 'inherit'};
|
||||
spawn('yarn', [script, ...args], spawnOptions).
|
||||
on('error', reject).
|
||||
on('exit', code => (code === 0 ? resolve : reject)());
|
||||
});
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ set +x -eu -o pipefail
|
||||
|
||||
# Install dependencies.
|
||||
echo -e "\nInstalling dependencies in '$aioDir'...\n-----"
|
||||
yarn install --frozen-lockfile
|
||||
yarn install --frozen-lockfile --non-interactive
|
||||
yarn update-webdriver
|
||||
|
||||
# Run checks for all URLs.
|
||||
|
@ -24,10 +24,14 @@ const SKIPPED_HTTPS_AUDITS = ['redirects-http'];
|
||||
const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/';
|
||||
|
||||
|
||||
// Specify the path and flags for Chrome on Travis
|
||||
// Specify the path and flags for Chrome on Travis.
|
||||
if (process.env.TRAVIS) {
|
||||
process.env.LIGHTHOUSE_CHROMIUM_PATH = process.env.CHROME_BIN;
|
||||
CHROME_LAUNCH_OPTS.chromeFlags = ['--no-sandbox'];
|
||||
}
|
||||
|
||||
// Be less verbose on CI.
|
||||
if (process.env.CI) {
|
||||
LIGHTHOUSE_FLAGS.logLevel = 'error';
|
||||
}
|
||||
|
||||
|
@ -56,9 +56,7 @@ export class ApiListComponent implements OnInit {
|
||||
|
||||
statuses: Option[] = [
|
||||
{ value: 'all', title: 'All' },
|
||||
{ value: 'stable', title: 'Stable' },
|
||||
{ value: 'deprecated', title: 'Deprecated' },
|
||||
{ value: 'experimental', title: 'Experimental' },
|
||||
{ value: 'security-risk', title: 'Security Risk' }
|
||||
];
|
||||
|
||||
|
@ -48,6 +48,26 @@ export const ELEMENT_MODULE_PATHS_AS_ROUTES = [
|
||||
selector: 'live-example',
|
||||
loadChildren: './live-example/live-example.module#LiveExampleModule'
|
||||
},
|
||||
{
|
||||
selector: 'aio-gs-interpolation',
|
||||
loadChildren: './getting-started/interpolation/interpolation.module#InterpolationModule'
|
||||
},
|
||||
{
|
||||
selector: 'aio-gs-property-binding',
|
||||
loadChildren: './getting-started/property-binding/property-binding.module#PropertyBindingModule'
|
||||
},
|
||||
{
|
||||
selector: 'aio-gs-event-binding',
|
||||
loadChildren: './getting-started/event-binding/event-binding.module#EventBindingModule'
|
||||
},
|
||||
{
|
||||
selector: 'aio-gs-ng-if',
|
||||
loadChildren: './getting-started/ng-if/ng-if.module#NgIfModule'
|
||||
},
|
||||
{
|
||||
selector: 'aio-gs-ng-for',
|
||||
loadChildren: './getting-started/ng-for/ng-for.module#NgForModule'
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,39 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ContainerComponent } from './container.component';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<aio-gs-container>
|
||||
<ng-container class="template">Template</ng-container>
|
||||
<ng-container class="data">Data</ng-container>
|
||||
<ng-container class="result">Result</ng-container>
|
||||
</aio-gs-container>
|
||||
`
|
||||
})
|
||||
export class TestComponent {}
|
||||
|
||||
describe('Getting Started Container Component', () => {
|
||||
let fixture: ComponentFixture<ContainerComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ContainerComponent, TestComponent ]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(TestComponent);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should project the content into the appropriate areas', () => {
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
const pre = compiled.querySelector('pre');
|
||||
const code = compiled.querySelector('code');
|
||||
const tabledata = compiled.querySelectorAll('td');
|
||||
|
||||
expect(pre.textContent).toContain('Template');
|
||||
expect(code.textContent).toContain('Data');
|
||||
expect(tabledata[2].textContent).toContain('Result');
|
||||
});
|
||||
});
|
@ -0,0 +1,80 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'aio-gs-container',
|
||||
template: `
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Template</th>
|
||||
<th>Data</th>
|
||||
<th>Result</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<pre><ng-content select=".template"></ng-content></pre>
|
||||
</td>
|
||||
<td>
|
||||
<code><ng-content select=".data"></ng-content></code>
|
||||
</td>
|
||||
<td><ng-content select=".result"></ng-content></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
code {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 760px),
|
||||
(min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* Force table to not be like tables anymore */
|
||||
table, thead, tbody, th, td, tr {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Hide table headers (but not display: none;, for accessibility) */
|
||||
thead tr {
|
||||
position: absolute;
|
||||
top: -9999px;
|
||||
left: -9999px;
|
||||
}
|
||||
|
||||
tr { border: 1px solid #ccc; }
|
||||
|
||||
td {
|
||||
/* Behave like a "row" */
|
||||
border: none;
|
||||
border-bottom: 1px solid #eee;
|
||||
position: relative;
|
||||
padding-top: 10%;
|
||||
}
|
||||
|
||||
td:before {
|
||||
/* Now like a table header */
|
||||
position: absolute;
|
||||
/* Top/left values mimic padding */
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
width: 45%;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
/* Label the data */
|
||||
td:nth-of-type(1):before { content: "Template"; }
|
||||
td:nth-of-type(2):before { content: "Data"; }
|
||||
td:nth-of-type(3):before { content: "Result"; }
|
||||
}
|
||||
`
|
||||
]
|
||||
})
|
||||
export class ContainerComponent { }
|
@ -0,0 +1,10 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ContainerComponent } from './container.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule ],
|
||||
declarations: [ ContainerComponent ],
|
||||
exports: [ ContainerComponent ]
|
||||
})
|
||||
export class ContainerModule { }
|
@ -0,0 +1,46 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ContainerModule } from '../container/container.module';
|
||||
import { EventBindingComponent } from './event-binding.component';
|
||||
import { createCustomEvent } from '../../../../testing/dom-utils';
|
||||
|
||||
describe('Getting Started Event Binding Component', () => {
|
||||
let component: EventBindingComponent;
|
||||
let fixture: ComponentFixture<EventBindingComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ ContainerModule ],
|
||||
declarations: [ EventBindingComponent ]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(EventBindingComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
|
||||
spyOn(window, 'alert');
|
||||
});
|
||||
|
||||
it('should update the name property on input change', () => {
|
||||
const text = 'Hello Angular';
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
const input: HTMLInputElement = compiled.querySelector('input');
|
||||
|
||||
|
||||
input.value = text;
|
||||
input.dispatchEvent(createCustomEvent(document, 'input', ''));
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.name).toBe(text);
|
||||
});
|
||||
|
||||
it('should display an alert when the button is clicked', () => {
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
const button: HTMLButtonElement = compiled.querySelector('button');
|
||||
|
||||
button.click();
|
||||
|
||||
expect(window.alert).toHaveBeenCalledWith('Hello, Angular!');
|
||||
});
|
||||
});
|
@ -0,0 +1,30 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'aio-gs-event-binding',
|
||||
template: `
|
||||
<aio-gs-container>
|
||||
<ng-container class="template"><button (click)="greet(name)">
|
||||
Greet
|
||||
</button></ng-container>
|
||||
|
||||
<ng-container class="data">
|
||||
name = '<input #input (input)="name = input.value" [value]="name">';
|
||||
</ng-container>
|
||||
|
||||
<ng-container class="result">
|
||||
<button (click)="greet(name)">
|
||||
Greet
|
||||
</button>
|
||||
</ng-container>
|
||||
</aio-gs-container>
|
||||
`,
|
||||
preserveWhitespaces: true
|
||||
})
|
||||
export class EventBindingComponent {
|
||||
name = 'Angular';
|
||||
|
||||
greet(name: string) {
|
||||
window.alert(`Hello, ${name}!`);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import { NgModule, Type } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { WithCustomElementComponent } from '../../element-registry';
|
||||
import { EventBindingComponent } from './event-binding.component';
|
||||
import { ContainerModule } from '../container/container.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule, ContainerModule ],
|
||||
declarations: [ EventBindingComponent ],
|
||||
exports: [ EventBindingComponent ],
|
||||
entryComponents: [ EventBindingComponent ]
|
||||
})
|
||||
export class EventBindingModule implements WithCustomElementComponent {
|
||||
customElementComponent: Type<any> = EventBindingComponent;
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { InterpolationComponent } from './interpolation.component';
|
||||
import { ContainerModule } from '../container/container.module';
|
||||
import { createCustomEvent } from '../../../../testing/dom-utils';
|
||||
|
||||
describe('Getting Started Interpolation Component', () => {
|
||||
let component: InterpolationComponent;
|
||||
let fixture: ComponentFixture<InterpolationComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ ContainerModule ],
|
||||
declarations: [ InterpolationComponent ]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(InterpolationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should update the siteName property on input change', () => {
|
||||
const text = 'Hello Angular';
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
const input: HTMLInputElement = compiled.querySelector('input');
|
||||
|
||||
input.value = text;
|
||||
input.dispatchEvent(createCustomEvent(document, 'input', ''));
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.siteName).toBe(text);
|
||||
});
|
||||
|
||||
it('should display the siteName', () => {
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
const header: HTMLHeadingElement = compiled.querySelector('h1');
|
||||
|
||||
expect(header.textContent).toContain('My Store');
|
||||
});
|
||||
});
|
@ -0,0 +1,20 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'aio-gs-interpolation',
|
||||
template: `
|
||||
<aio-gs-container>
|
||||
<ng-container class="template"><h1>Welcome to {{'{'+'{'}}siteName{{'}'+'}'}}<h1></ng-container>
|
||||
|
||||
<ng-container class="data">
|
||||
siteName = '<input #input (input)="siteName = input.value" [value]="siteName">';
|
||||
</ng-container>
|
||||
|
||||
<ng-container class="result"><h1>Welcome to {{ siteName }}</h1></ng-container>
|
||||
</aio-gs-container>
|
||||
`
|
||||
})
|
||||
export class InterpolationComponent {
|
||||
siteName = 'My Store';
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import { NgModule, Type } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { WithCustomElementComponent } from '../../element-registry';
|
||||
import { InterpolationComponent } from './interpolation.component';
|
||||
import { ContainerModule } from '../container/container.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule, ContainerModule ],
|
||||
declarations: [ InterpolationComponent ],
|
||||
exports: [ InterpolationComponent ],
|
||||
entryComponents: [ InterpolationComponent ]
|
||||
})
|
||||
export class InterpolationModule implements WithCustomElementComponent {
|
||||
customElementComponent: Type<any> = InterpolationComponent;
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { NgForComponent } from './ng-for.component';
|
||||
import { ContainerModule } from '../container/container.module';
|
||||
import { ProductService } from '../product.service';
|
||||
|
||||
describe('Getting Started NgFor Component', () => {
|
||||
let component: NgForComponent;
|
||||
let fixture: ComponentFixture<NgForComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ ContainerModule ],
|
||||
declarations: [ NgForComponent ],
|
||||
providers: [ ProductService ]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(NgForComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should display the products', () => {
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
const spans = compiled.querySelectorAll('span');
|
||||
|
||||
expect(spans[0]!.textContent).toContain('Shoes');
|
||||
expect(spans[1]!.textContent).toContain('Phones');
|
||||
});
|
||||
|
||||
it('should display an error message if provided products JSON is invalid', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
component.productsData$.next('bad');
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
component.parseError$.subscribe(error => {
|
||||
expect(error).toBeTruthy();
|
||||
})
|
||||
});
|
||||
});
|
@ -0,0 +1,46 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { ProductService } from '../product.service';
|
||||
|
||||
@Component({
|
||||
selector: 'aio-gs-ng-for',
|
||||
template: `
|
||||
<aio-gs-container>
|
||||
<ng-container class="template"><span *ngFor="let product of products">
|
||||
{{'{'+'{'}}product{{'}'+'}'}}
|
||||
</span></ng-container>
|
||||
|
||||
<ng-container class="data">
|
||||
products = <input #input (input)="productsData$.next(input.value)" [value]="productsData$ | async">;
|
||||
<div *ngIf="parseError$ | async" class="material-icons" matTooltip="The provided JSON is invalid">error_outline</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container class="result">
|
||||
<span *ngFor="let product of products$ | async">{{product}}</span>
|
||||
</ng-container>
|
||||
</aio-gs-container>
|
||||
`,
|
||||
styles: [`
|
||||
span::after {
|
||||
content: ' ';
|
||||
}
|
||||
`],
|
||||
preserveWhitespaces: true
|
||||
})
|
||||
export class NgForComponent implements OnInit, OnDestroy {
|
||||
productsData$ = this.productService.productsData$;
|
||||
products$ = this.productService.products$;
|
||||
parseError$ = this.productService.parseError$;
|
||||
productsSub: Subscription;
|
||||
|
||||
constructor(private productService: ProductService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.productsSub = this.productService.init().subscribe();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.productsSub.unsubscribe();
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import { NgModule, Type } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { WithCustomElementComponent } from '../../element-registry';
|
||||
import { NgForComponent } from './ng-for.component';
|
||||
import { ContainerModule } from '../container/container.module';
|
||||
import { ProductService } from '../product.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule, ContainerModule, MatTooltipModule ],
|
||||
declarations: [ NgForComponent ],
|
||||
exports: [ NgForComponent ],
|
||||
entryComponents: [ NgForComponent ],
|
||||
providers: [ ProductService ]
|
||||
})
|
||||
export class NgForModule implements WithCustomElementComponent {
|
||||
customElementComponent: Type<any> = NgForComponent;
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { NgIfComponent } from './ng-if.component';
|
||||
import { ContainerModule } from '../container/container.module';
|
||||
import { ProductService } from '../product.service';
|
||||
|
||||
describe('Getting Started NgIf Component', () => {
|
||||
let component: NgIfComponent;
|
||||
let fixture: ComponentFixture<NgIfComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ ContainerModule ],
|
||||
declarations: [ NgIfComponent ],
|
||||
providers: [ ProductService ]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(NgIfComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should display the message if products are listed', () => {
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
const paragraph = compiled.querySelector('p');
|
||||
|
||||
expect(paragraph.textContent).toContain('available');
|
||||
});
|
||||
|
||||
it('should not display the message if products list is empty', () => {
|
||||
component.products$.next([]);
|
||||
fixture.detectChanges();
|
||||
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
const paragraph = compiled.querySelector('p');
|
||||
|
||||
expect(paragraph).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should display an error message if provided products JSON is invalid', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
component.productsData$.next('bad');
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
component.parseError$.subscribe(error => {
|
||||
expect(error).toBeTruthy();
|
||||
})
|
||||
});
|
||||
});
|
@ -0,0 +1,43 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { ProductService } from '../product.service';
|
||||
|
||||
@Component({
|
||||
selector: 'aio-gs-ng-if',
|
||||
template: `
|
||||
<aio-gs-container>
|
||||
<ng-container class="template"><p *ngIf="products.length > 0">
|
||||
We still have products available.
|
||||
</p></ng-container>
|
||||
|
||||
<ng-container class="data">
|
||||
products = <input #input (input)="productsData$.next(input.value)" [value]="productsData$ | async">;
|
||||
<div *ngIf="parseError$ | async" class="material-icons" matTooltip="The provided JSON is invalid">error_outline</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container class="result">
|
||||
<p *ngIf="(products$ | async)?.length > 0">
|
||||
We still have products available.
|
||||
</p>
|
||||
</ng-container>
|
||||
</aio-gs-container>
|
||||
`,
|
||||
preserveWhitespaces: true
|
||||
})
|
||||
export class NgIfComponent implements OnInit, OnDestroy {
|
||||
productsData$ = this.productService.productsData$;
|
||||
products$ = this.productService.products$;
|
||||
parseError$ = this.productService.parseError$;
|
||||
productsSub: Subscription;
|
||||
|
||||
constructor(private productService: ProductService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.productsSub = this.productService.init().subscribe();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.productsSub.unsubscribe();
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import { NgModule, Type } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { WithCustomElementComponent } from '../../element-registry';
|
||||
import { NgIfComponent } from './ng-if.component';
|
||||
import { ContainerModule } from '../container/container.module';
|
||||
import { ProductService } from '../product.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule, ContainerModule, MatTooltipModule ],
|
||||
declarations: [ NgIfComponent ],
|
||||
exports: [ NgIfComponent ],
|
||||
entryComponents: [ NgIfComponent ],
|
||||
providers: [ ProductService ]
|
||||
})
|
||||
export class NgIfModule implements WithCustomElementComponent {
|
||||
customElementComponent: Type<any> = NgIfComponent;
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import { tap, debounceTime } from 'rxjs/operators';
|
||||
|
||||
export const PRODUCTS = ['Shoes', 'Phones'];
|
||||
|
||||
@Injectable()
|
||||
export class ProductService {
|
||||
productsData$ = new BehaviorSubject(JSON.stringify(PRODUCTS));
|
||||
products$ = new BehaviorSubject<string[]>(PRODUCTS);
|
||||
parseError$ = new Subject<boolean>();
|
||||
|
||||
init() {
|
||||
return this.productsData$.pipe(
|
||||
debounceTime(250),
|
||||
tap(data => {
|
||||
let parsed;
|
||||
|
||||
try {
|
||||
parsed = JSON.parse(data);
|
||||
} catch (e) {
|
||||
parsed = null;
|
||||
}
|
||||
|
||||
if (parsed && Array.isArray(parsed)) {
|
||||
this.products$.next(parsed);
|
||||
this.parseError$.next(false);
|
||||
} else {
|
||||
this.parseError$.next(true);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PropertyBindingComponent } from './property-binding.component';
|
||||
import { ContainerModule } from '../container/container.module';
|
||||
import { createCustomEvent } from '../../../../testing/dom-utils';
|
||||
|
||||
describe('Getting Started Property Binding Component', () => {
|
||||
let component: PropertyBindingComponent;
|
||||
let fixture: ComponentFixture<PropertyBindingComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ ContainerModule ],
|
||||
declarations: [ PropertyBindingComponent ]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(PropertyBindingComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update the image title on input change', () => {
|
||||
const text = 'Hello Angular';
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
const input: HTMLInputElement = compiled.querySelector('input');
|
||||
|
||||
input.value = text;
|
||||
input.dispatchEvent(createCustomEvent(document, 'input', ''));
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.imageTitle).toBe(text);
|
||||
});
|
||||
|
||||
it('should display the image title', () => {
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
const image: HTMLImageElement = compiled.querySelector('img');
|
||||
|
||||
expect(image.getAttribute('title')).toContain('Angular Logo');
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,21 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'aio-gs-property-binding',
|
||||
template: `
|
||||
<aio-gs-container>
|
||||
<ng-container class="template"><img ... [title]="imageTitle"></ng-container>
|
||||
|
||||
<ng-container class="data">
|
||||
imageTitle = '<input #input (input)="imageTitle = input.value" [value]="imageTitle">';
|
||||
</ng-container>
|
||||
|
||||
<ng-container class="result">
|
||||
<img src="/assets/images/logos/angular/angular.svg" width="37" height="40" [title]="imageTitle">
|
||||
</ng-container>
|
||||
</aio-gs-container>
|
||||
`
|
||||
})
|
||||
export class PropertyBindingComponent {
|
||||
imageTitle = 'Angular Logo';
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import { NgModule, Type } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { WithCustomElementComponent } from '../../element-registry';
|
||||
import { PropertyBindingComponent } from './property-binding.component';
|
||||
import { ContainerModule } from '../container/container.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule, ContainerModule ],
|
||||
declarations: [ PropertyBindingComponent ],
|
||||
exports: [ PropertyBindingComponent ],
|
||||
entryComponents: [ PropertyBindingComponent ]
|
||||
})
|
||||
export class PropertyBindingModule implements WithCustomElementComponent {
|
||||
customElementComponent: Type<any> = PropertyBindingComponent;
|
||||
}
|
@ -123,7 +123,7 @@ td {
|
||||
padding: 8px 30px;
|
||||
letter-spacing: 0.30px;
|
||||
|
||||
p {
|
||||
p:first-child, p:last-child {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
.api-body {
|
||||
|
||||
max-width: 1200px;
|
||||
|
||||
table {
|
||||
margin: 12px 0 24px;
|
||||
|
||||
th {
|
||||
text-transform: none;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
tr {
|
||||
border-bottom: 1px solid $lightgray;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.item-table {
|
||||
td {
|
||||
padding: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
&.list-table {
|
||||
td {
|
||||
padding: 16px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.short-description {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
LAYOUT STYLES
|
||||
============================== */
|
||||
|
||||
@import 'api-pages';
|
||||
@import 'content-layout';
|
||||
@import 'doc-viewer';
|
||||
@import 'footer';
|
||||
|
@ -1,13 +1,111 @@
|
||||
.github-links {
|
||||
float: right;
|
||||
.material-icons {
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
font-size: 20px;
|
||||
&:hover {
|
||||
background-color: $mist;
|
||||
.api-body {
|
||||
max-width: 1200px;
|
||||
|
||||
table {
|
||||
margin: 12px 0 24px;
|
||||
|
||||
th {
|
||||
text-transform: none;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
tr {
|
||||
border-bottom: 1px solid $lightgray;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
// This is overriding a style here:
|
||||
// https://github.com/angular/angular/blob/95993e1/aio/src/styles/2-modules/_table.scss#L58-L62
|
||||
tbody > tr > td tr td:first-child {
|
||||
@media screen and (max-width: 480px) {
|
||||
background-color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.item-table {
|
||||
td {
|
||||
padding: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
&.list-table {
|
||||
td {
|
||||
padding: 16px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.short-description {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&.parameters-table {
|
||||
margin-top: 0;
|
||||
font-size: 14px;
|
||||
box-shadow: none;
|
||||
|
||||
tr {
|
||||
@media screen and (max-width: 480px) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
font-weight: 600;
|
||||
padding-left: 16px;
|
||||
width: 20%;
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 8px 8px 8px 0;
|
||||
border: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.class-overview {
|
||||
position: relative;
|
||||
|
||||
code-example {
|
||||
clear: left;
|
||||
}
|
||||
}
|
||||
|
||||
.short-description {
|
||||
margin: 6px 0 0 10px;
|
||||
}
|
||||
|
||||
.properties-table {
|
||||
font-size: 14px;
|
||||
|
||||
thead th {
|
||||
&:nth-child(1) {
|
||||
width: 20%;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
width: 20%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.api-header {
|
||||
@ -18,6 +116,22 @@
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: -4px;
|
||||
}
|
||||
}
|
||||
|
||||
.github-links {
|
||||
float: right;
|
||||
.material-icons {
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
font-size: 20px;
|
||||
&:hover {
|
||||
background-color: $mist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.api-body {
|
||||
@ -65,10 +179,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.api-heading {
|
||||
padding: 5px 0;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.parameters-table {
|
||||
@ -80,21 +194,71 @@
|
||||
}
|
||||
|
||||
details.overloads {
|
||||
margin-left: -8px;
|
||||
box-shadow: none;
|
||||
|
||||
.icon-action-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-contents {
|
||||
padding: 0;
|
||||
border: 1px solid $lightgray;
|
||||
border-radius: 2px;
|
||||
box-shadow: none;
|
||||
|
||||
> *:not(hr) {
|
||||
margin: 16px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
summary {
|
||||
height: inherit;
|
||||
padding: 8px 12px;
|
||||
padding: 0;
|
||||
|
||||
h4 {
|
||||
margin: 0;
|
||||
clear: left;
|
||||
}
|
||||
|
||||
.show-all {
|
||||
display: initial;
|
||||
}
|
||||
.collapse-all {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&[open] > summary {
|
||||
.show-all {
|
||||
display: none;
|
||||
}
|
||||
.collapse-all {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
details.overload {
|
||||
box-shadow: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
.from-constructor, .read-only-property, .write-only-property {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.5px;
|
||||
font-style: italic;
|
||||
color: $blue;
|
||||
background-color: $lightgray;
|
||||
border-radius: 4px;
|
||||
padding: 4px 6px;
|
||||
}
|
||||
|
||||
.ngmodule-list {
|
||||
@ -120,10 +284,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.member-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.deprecated-api-item {
|
||||
|
@ -1,7 +1,10 @@
|
||||
.cli-name, .cli-default {
|
||||
.cli-name {
|
||||
font-weight: bold;
|
||||
|
||||
.kwd { color: initial } /* override code format */
|
||||
}
|
||||
|
||||
.cli-option-syntax {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
|
@ -25,14 +25,7 @@ summary {
|
||||
display: none; // Remove the built in details marker in webkit
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '\E5CE'; // See https://material.io/icons/#ic_expand_less
|
||||
font-family: 'Material Icons';
|
||||
font-size: 24px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
@include rotate(0deg); // We will rotate 180 degrees when details is open
|
||||
float: right;
|
||||
}
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
details {
|
||||
@ -42,7 +35,11 @@ details {
|
||||
padding: 16px 24px;
|
||||
}
|
||||
|
||||
&[open] > summary::before {
|
||||
@include rotate(180deg); // Rotate the icon
|
||||
// Rotate the icon
|
||||
summary i.material-icons.expand {
|
||||
@include rotate(0deg);
|
||||
}
|
||||
&[open] > summary i.material-icons.expand {
|
||||
@include rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,3 @@ hr {
|
||||
background: $lightgray;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.hr-margin {
|
||||
display: block;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 16px;
|
||||
padding: 0;
|
||||
}
|
@ -3,8 +3,8 @@
|
||||
============================== */
|
||||
|
||||
@import 'alert';
|
||||
@import 'api-pages';
|
||||
@import 'api-list';
|
||||
@import 'api-pages';
|
||||
@import 'buttons';
|
||||
@import 'callout';
|
||||
@import 'card';
|
||||
|
16
aio/src/testing/dom-utils.ts
Normal file
16
aio/src/testing/dom-utils.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Create a `CustomEvent` (even on browsers where `CustomEvent` is not a constructor).
|
||||
*/
|
||||
export function createCustomEvent(doc: Document, name: string, detail: any): CustomEvent {
|
||||
const bubbles = false;
|
||||
const cancelable = false;
|
||||
|
||||
// On IE9-11, `CustomEvent` is not a constructor.
|
||||
if (typeof CustomEvent !== 'function') {
|
||||
const event = doc.createEvent('CustomEvent');
|
||||
event.initCustomEvent(name, bubbles, cancelable, detail);
|
||||
return event;
|
||||
}
|
||||
|
||||
return new CustomEvent(name, {bubbles, cancelable, detail});
|
||||
}
|
@ -3,9 +3,11 @@
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./*.e2e-spec.ts'
|
||||
],
|
||||
suites: {
|
||||
full: './*.e2e-spec.ts',
|
||||
smoke: './smoke-tests.e2e-spec.ts',
|
||||
},
|
||||
suite: 'full',
|
||||
capabilities: {
|
||||
browserName: 'chrome',
|
||||
// For Travis
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user