mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
148 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e6452d604 | |||
| 4ccd845081 | |||
| 6e4d8f65cf | |||
| 5810827de4 | |||
| 03127fc870 | |||
| bf1f9a0897 | |||
| 3b46066ff0 | |||
| b0b004e3ff | |||
| ffd25fcfbe | |||
| a31dcb993f | |||
| 5b4a5eb0e9 | |||
| 7b40d74fb4 | |||
| 82712f80df | |||
| 65d69157cb | |||
| 684891a63e | |||
| cc57b24881 | |||
| f6f3783a3d | |||
| febbca5124 | |||
| 38c6fa1cee | |||
| c700418ab8 | |||
| 867b380f64 | |||
| 975cb05819 | |||
| 2579592be6 | |||
| 7ce89a2e94 | |||
| 4051930b8c | |||
| 0de326271b | |||
| a734ca3e15 | |||
| c2fac37717 | |||
| 6d3c497c9d | |||
| 37aad5aa04 | |||
| 1122afd656 | |||
| 9fc808c129 | |||
| 608f5e7cd1 | |||
| f0ff388731 | |||
| 4721208d5a | |||
| fcfa173270 | |||
| dcf6b01f0d | |||
| 8ce22ebae3 | |||
| 137195cd26 | |||
| af9cd84c13 | |||
| c14c7cc191 | |||
| f56b6555bd | |||
| 7bb4f9126b | |||
| ab1e8c8667 | |||
| b1a3925794 | |||
| 7842d06bbd | |||
| 23db70f2d0 | |||
| d2343f2ca8 | |||
| 055448e9c6 | |||
| 3fd41a14cd | |||
| ba46365abd | |||
| 9cc424019e | |||
| 16e25aa01b | |||
| 68d6fae734 | |||
| 3ef0295572 | |||
| 19930f3ffa | |||
| a258823071 | |||
| cc9f5cb3aa | |||
| d140dd2d41 | |||
| 587093c3a5 | |||
| dc4f77c851 | |||
| c99624d078 | |||
| e8a36a7b81 | |||
| 5c4cf07f4d | |||
| 646fe3c5fb | |||
| a5e98aa338 | |||
| 5c36fc784f | |||
| 04c6574280 | |||
| e6b301caa2 | |||
| 403833557b | |||
| 97a40958b5 | |||
| dbd761f528 | |||
| dcd1add06f | |||
| 8081fdd22d | |||
| 6e5b865710 | |||
| 0c7c852ee7 | |||
| a06140a2ca | |||
| 20d62603c2 | |||
| 14941b9b79 | |||
| 0ad738658e | |||
| b7732f79db | |||
| 554305976b | |||
| 6f4a5c325d | |||
| 546a8e52dd | |||
| 02894382f3 | |||
| fbd5d0e7b5 | |||
| 5af3642f65 | |||
| 03fc92d448 | |||
| 76860b54b9 | |||
| fb296e4dd7 | |||
| 157415831c | |||
| 6208865206 | |||
| 0606eca25e | |||
| 4fe88cf9af | |||
| 94a361b543 | |||
| bf0f80e5d6 | |||
| b0396e7164 | |||
| 7f0563eb6e | |||
| 6dc2b22426 | |||
| 36f434e49d | |||
| 4b0ef5acfb | |||
| a1e923e2f4 | |||
| 39ace8664b | |||
| 2c65ea9b40 | |||
| 3dbfabcafe | |||
| cf463a6f4f | |||
| a43c0772ea | |||
| bd4d2bbc1e | |||
| 4a2492380c | |||
| 4b46819ed1 | |||
| 7a090eee96 | |||
| da68bead56 | |||
| 543b98e1f8 | |||
| 03619ada72 | |||
| d8e5316eca | |||
| 77efeb5933 | |||
| 252b111d1e | |||
| 1c41633483 | |||
| 9f977e0f34 | |||
| 3e19890967 | |||
| 074fd4a5ec | |||
| 094d733654 | |||
| 2fff344cd6 | |||
| 951ef93aa6 | |||
| f30a49e3de | |||
| c48e1cc4ed | |||
| 198834b731 | |||
| 6a8c030ab1 | |||
| 232a8c1b8d | |||
| 8f944e0752 | |||
| af0c8b8fa8 | |||
| ee19395672 | |||
| 096fdd0f59 | |||
| 9998bee5f4 | |||
| 95387047fd | |||
| 899e51ad8e | |||
| 0ba2b5e5c3 | |||
| 9f490da7e2 | |||
| b95b5b55d8 | |||
| 26781fd0fe | |||
| f79fd35042 | |||
| dfa772d686 | |||
| c7c0723c7f | |||
| e01549b26b | |||
| cf62063174 | |||
| c0c6d1d892 | |||
| d1fa6cd7d9 | |||
| 1472515d68 |
@@ -6,7 +6,6 @@
|
||||
node_modules
|
||||
dist
|
||||
aio/node_modules
|
||||
aio/content/example-playground
|
||||
aio/tools/examples/shared/node_modules
|
||||
aio/tools/examples/shared/example-scaffold
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ build:remote --platforms=@npm//@angular/build-tooling/bazel/remote-execution:pla
|
||||
|
||||
# Remote instance and caching
|
||||
build:remote --remote_instance_name=projects/internal-200822/instances/primary_instance
|
||||
build:remote --project_id=internal-200822
|
||||
build:remote --bes_instance_name=internal-200822
|
||||
build:remote --remote_cache=remotebuildexecution.googleapis.com
|
||||
build:remote --remote_executor=remotebuildexecution.googleapis.com
|
||||
|
||||
|
||||
+2
-255
@@ -89,7 +89,7 @@ executors:
|
||||
type: string
|
||||
default: medium
|
||||
docker:
|
||||
- image: cimg/node:16.14.0
|
||||
- image: cimg/node:18.13.0
|
||||
resource_class: << parameters.resource_class >>
|
||||
working_directory: ~/ng
|
||||
|
||||
@@ -99,7 +99,7 @@ executors:
|
||||
type: string
|
||||
default: medium
|
||||
docker:
|
||||
- image: cimg/node:16.14.0-browsers
|
||||
- image: cimg/node:18.13.0-browsers
|
||||
resource_class: << parameters.resource_class >>
|
||||
working_directory: ~/ng
|
||||
|
||||
@@ -249,42 +249,6 @@ jobs:
|
||||
- ./ng
|
||||
- ./bazel_repository_cache
|
||||
|
||||
test:
|
||||
executor:
|
||||
name: test-browser-executor
|
||||
# Now that large integration tests are running locally in parallel (they can't run on RBE yet
|
||||
# as they require network access for yarn install), this test is running out of memory
|
||||
# consistently with the xlarge machine.
|
||||
# TODO: switch back to xlarge once integration tests are running on remote-exec
|
||||
resource_class: 2xlarge+
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- run:
|
||||
# We need to explicitly specify the --symlink_prefix option because otherwise we would
|
||||
# not be able to easily find the output bin directory when uploading artifacts for size
|
||||
# measurements.
|
||||
command: yarn test:ci
|
||||
no_output_timeout: 20m
|
||||
# Publish bundle artifacts which will be used to calculate the size change. **Note**: Make
|
||||
# sure that the size plugin from the Angular robot fetches the artifacts from this CircleCI
|
||||
# job (see .github/angular-robot.yml). Additionally any artifacts need to be stored with the
|
||||
# following path format: "{projectName}/{context}/{fileName}". This format is necessary
|
||||
# because otherwise the bot is not able to pick up the artifacts from CircleCI. See:
|
||||
# https://github.com/angular/github-robot/blob/master/functions/src/plugins/size.ts#L392-L394
|
||||
- store_artifacts:
|
||||
path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js
|
||||
destination: core/hello_world/bundle
|
||||
- store_artifacts:
|
||||
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js
|
||||
destination: core/todo/bundle
|
||||
- store_artifacts:
|
||||
path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js.br
|
||||
destination: core/hello_world/bundle.br
|
||||
- store_artifacts:
|
||||
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.br
|
||||
destination: core/todo/bundle.br
|
||||
|
||||
# NOTE: This is currently limited to main builds only. See the `monitoring` configuration.
|
||||
saucelabs:
|
||||
executor:
|
||||
@@ -312,48 +276,6 @@ jobs:
|
||||
- notify_webhook_on_fail:
|
||||
webhook_url_env_var: SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL
|
||||
|
||||
test_aio:
|
||||
executor:
|
||||
name: test-browser-executor
|
||||
resource_class: 2xlarge+
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
|
||||
# Run all aio tests
|
||||
- run:
|
||||
command: yarn --cwd aio test:ci
|
||||
no_output_timeout: 20m
|
||||
|
||||
# Check the bundle sizes.
|
||||
- run: yarn --cwd aio payload-size
|
||||
|
||||
deploy_aio:
|
||||
executor:
|
||||
name: test-browser-executor
|
||||
resource_class: 2xlarge+
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
# Deploy angular.io to production (if necessary)
|
||||
- run: setPublicVar_CI_STABLE_BRANCH
|
||||
- run: yarn --cwd aio deploy-production
|
||||
|
||||
test_aio_local:
|
||||
executor:
|
||||
name: test-browser-executor
|
||||
resource_class: 2xlarge+
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
# Run all aio tests (with local Angular packages)
|
||||
- run:
|
||||
command: yarn --cwd aio test-local:ci
|
||||
no_output_timeout: 20m
|
||||
|
||||
# Check the bundle sizes.
|
||||
- run: yarn --cwd aio payload-size aio-local
|
||||
|
||||
# The `build-npm-packages` tasks exist for backwards-compatibility with old scripts and
|
||||
# tests that rely on the pre-Bazel `dist/packages-dist` output structure (build.sh).
|
||||
# Having multiple jobs that independently build in this manner duplicates some work; we build
|
||||
@@ -385,47 +307,6 @@ jobs:
|
||||
- ~/bazel_repository_cache
|
||||
- ~/.cache/bazelisk
|
||||
|
||||
# This job creates compressed tarballs (`.tgz` files) for all Angular packages and stores them as
|
||||
# build artifacts. This makes it easy to try out changes from a PR build for testing purposes.
|
||||
# More info CircleCI build artifacts: https://circleci.com/docs/2.0/artifacts
|
||||
#
|
||||
# NOTE: Currently, this job only runs for PR builds. See `publish_snapshot` for non-PR builds.
|
||||
publish_packages_as_artifacts:
|
||||
executor: default-executor
|
||||
environment:
|
||||
AIMWA_PACKAGES_DIR: &aimwa_packages_dir 'dist/angular-in-memory-web-api-dist'
|
||||
AIMWA_PACKAGES_ARCHIVES_DIR: &aimwa_packages_archives_dir 'dist/angular-in-memory-web-api-dist-archives'
|
||||
NG_PACKAGES_DIR: &ng_packages_dir 'dist/packages-dist'
|
||||
NG_PACKAGES_ARCHIVES_DIR: &ng_packages_archives_dir 'dist/packages-dist-archives'
|
||||
ZONEJS_PACKAGES_DIR: &zonejs_packages_dir 'dist/zone.js-dist'
|
||||
ZONEJS_PACKAGES_ARCHIVES_DIR: &zonejs_packages_archives_dir 'dist/zone.js-dist-archives'
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
# Publish `@angular/*` packages.
|
||||
- run:
|
||||
name: Create artifacts for @angular/* packages
|
||||
command: ./scripts/ci/create-package-archives.sh $CI_BRANCH $CI_COMMIT $NG_PACKAGES_DIR $NG_PACKAGES_ARCHIVES_DIR
|
||||
- store_artifacts:
|
||||
path: *ng_packages_archives_dir
|
||||
destination: angular
|
||||
# Publish the `angular-in-memory-web-api` package.
|
||||
- run:
|
||||
name: Create artifacts for the `angular-in-memory-web-api` package
|
||||
# Need to remove the zone.js.tgz before archive
|
||||
command: ./scripts/ci/create-package-archives.sh $CI_BRANCH $CI_COMMIT $AIMWA_PACKAGES_DIR $AIMWA_PACKAGES_ARCHIVES_DIR
|
||||
- store_artifacts:
|
||||
path: *aimwa_packages_archives_dir
|
||||
destination: angular-in-memory-web-api
|
||||
# Publish the `zone.js` package.
|
||||
- run:
|
||||
name: Create artifacts for the `zone.js` package
|
||||
# Need to remove the zone.js.tgz before archive
|
||||
command: rm -rf $ZONEJS_PACKAGES_DIR/archive && ./scripts/ci/create-package-archives.sh $CI_BRANCH $CI_COMMIT $ZONEJS_PACKAGES_DIR $ZONEJS_PACKAGES_ARCHIVES_DIR
|
||||
- store_artifacts:
|
||||
path: *zonejs_packages_archives_dir
|
||||
destination: zone.js
|
||||
|
||||
# This job updates the content of repos like github.com/angular/core-builds
|
||||
# for every green build on angular/angular.
|
||||
publish_snapshot:
|
||||
@@ -442,14 +323,6 @@ jobs:
|
||||
command: echo "https://${SNAPSHOT_BUILDS_GITHUB_TOKEN}:@github.com" > ${HOME}/.git_credentials
|
||||
- run: ./scripts/ci/publish-build-artifacts.sh
|
||||
|
||||
aio_misc:
|
||||
executor: default-executor
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- run:
|
||||
name: Check website provided in contributors.json file
|
||||
command: yarn node aio/scripts/test-external-urls.js
|
||||
|
||||
aio_monitoring_stable:
|
||||
executor: test-browser-executor
|
||||
steps:
|
||||
@@ -485,97 +358,6 @@ jobs:
|
||||
- notify_webhook_on_fail:
|
||||
webhook_url_env_var: SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL
|
||||
|
||||
legacy-unit-tests-saucelabs:
|
||||
executor:
|
||||
name: default-executor
|
||||
# In order to avoid the bottleneck of having a slow host machine, we acquire a better
|
||||
# container for this job. This is necessary because we launch a lot of browsers concurrently
|
||||
# and therefore the tunnel and Karma need to process a lot of file requests and tests.
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- init_saucelabs_environment
|
||||
- run:
|
||||
name: Starting Saucelabs tunnel service
|
||||
command: ./tools/saucelabs/sauce-service.sh run
|
||||
background: true
|
||||
# Build test fixtures for a test that rely on Bazel-generated fixtures. Note that disabling
|
||||
# specific tests which are reliant on such generated fixtures is not an option as SystemJS
|
||||
# in the Saucelabs legacy job always fetches referenced files, even if the imports would be
|
||||
# guarded by an check to skip in the Saucelabs legacy job. We should be good running such
|
||||
# test in all supported browsers on Saucelabs anyway until this job can be removed.
|
||||
- run:
|
||||
name: Preparing Bazel-generated fixtures required in legacy tests
|
||||
command: |
|
||||
yarn bazel build \
|
||||
//packages/core/test:downleveled_es5_fixture \
|
||||
//packages/common/locales
|
||||
|
||||
# Needed for the ES5 downlevel reflector test in `packages/core/test/reflection`.
|
||||
mkdir -p dist/legacy-test-out/core/test/reflection/
|
||||
cp dist/bin/packages/core/test/reflection/es5_downleveled_inheritance_fixture.js \
|
||||
dist/legacy-test-out/core/test/reflection/es5_downleveled_inheritance_fixture.js
|
||||
# Locale files are needed for i18n tests running within Saucelabs. These are added
|
||||
# directly as sources so that the TypeScript compilation of `/packages/tsconfig.json`
|
||||
# can succeed. Note that the base locale and currencies files are checked-in, so
|
||||
# we do not need to re-generate those through Bazel.
|
||||
mkdir -p packages/common/locales/extra
|
||||
cp dist/bin/packages/common/locales/*.ts packages/common/locales
|
||||
cp dist/bin/packages/common/locales/extra/*.ts packages/common/locales/extra
|
||||
# Build the bundle for all tests to run within Saucelabs
|
||||
- run: node tools/legacy-saucelabs/build-saucelabs-test-bundle.mjs
|
||||
- run:
|
||||
# Waiting on ready ensures that we don't run tests too early without Saucelabs not being ready.
|
||||
name: Waiting for Saucelabs tunnel to connect
|
||||
command: ./tools/saucelabs/sauce-service.sh ready-wait
|
||||
- run:
|
||||
name: Running tests on Saucelabs.
|
||||
command: |
|
||||
KARMA_WEB_TEST_MODE=SL_REQUIRED yarn karma start ./karma-js.conf.js --single-run
|
||||
- run:
|
||||
name: Stop Saucelabs tunnel service
|
||||
command: ./tools/saucelabs/sauce-service.sh stop
|
||||
|
||||
test_zonejs:
|
||||
executor:
|
||||
name: default-executor
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- install_java
|
||||
|
||||
- run: |
|
||||
yarn bazel build -- \
|
||||
//packages/zone.js/bundles:zone.umd.js \
|
||||
//packages/zone.js:npm_package \
|
||||
//packages/zone.js/test/closure:closure_js \
|
||||
//packages/zone.js:zone_externs
|
||||
|
||||
- run: |
|
||||
mkdir -p packages/zone.js/build/
|
||||
mkdir -p packages/zone.js/build/test/
|
||||
mkdir -p packages/zone.js/test/
|
||||
|
||||
cp dist/bin/packages/zone.js/bundles/zone.umd.js packages/zone.js/build/zone.umd.js
|
||||
cp dist/bin/packages/zone.js/npm_package/bundles/zone-mix.umd.js ./packages/zone.js/test/extra/
|
||||
cp dist/bin/packages/zone.js/npm_package/bundles/zone-patch-electron.umd.js ./packages/zone.js/test/extra/
|
||||
cp dist/bin/packages/zone.js/test/closure/zone.closure.mjs ./packages/zone.js/build/test/zone.closure.mjs
|
||||
cp dist/bin/packages/zone.js/zone_externs.js ./packages/zone.js/build/zone_externs.js
|
||||
|
||||
# Install
|
||||
- run: yarn --cwd packages/zone.js install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
|
||||
# Run zone.js tools tests
|
||||
- run: yarn --cwd packages/zone.js promisetest
|
||||
- run: yarn --cwd packages/zone.js promisefinallytest
|
||||
- run: yarn --cwd packages/zone.js jest:test
|
||||
- run: yarn --cwd packages/zone.js jest:nodetest
|
||||
- run: yarn --cwd packages/zone.js electrontest
|
||||
- run: yarn --cwd packages/zone.js closuretest
|
||||
- run: yarn --cwd packages/zone.js/test/typings install --frozen-lockfile --non-interactive --cache-folder ~/.cache/yarn
|
||||
- run: yarn --cwd packages/zone.js/test/typings test
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
default_workflow:
|
||||
@@ -584,54 +366,19 @@ workflows:
|
||||
filters:
|
||||
branches:
|
||||
ignore: g3
|
||||
- test:
|
||||
requires:
|
||||
- setup
|
||||
- build-npm-packages:
|
||||
requires:
|
||||
- setup
|
||||
- legacy-unit-tests-saucelabs:
|
||||
requires:
|
||||
- setup
|
||||
- test_aio:
|
||||
requires:
|
||||
- setup
|
||||
- deploy_aio:
|
||||
requires:
|
||||
- test_aio
|
||||
- test_aio_local:
|
||||
requires:
|
||||
- setup
|
||||
- publish_packages_as_artifacts:
|
||||
requires:
|
||||
- build-npm-packages
|
||||
- publish_snapshot:
|
||||
<<: *only_release_branches
|
||||
requires:
|
||||
# Only publish if tests and integration tests pass
|
||||
- test
|
||||
# Only publish if `aio`/`docs` tests using the locally built Angular packages pass
|
||||
- test_aio_local
|
||||
# Get the artifacts to publish from the build-packages-dist job
|
||||
# since the publishing script expects the legacy outputs layout.
|
||||
- build-npm-packages
|
||||
- legacy-unit-tests-saucelabs
|
||||
- test_zonejs:
|
||||
requires:
|
||||
- setup
|
||||
|
||||
monitoring:
|
||||
jobs:
|
||||
- setup
|
||||
- aio_misc:
|
||||
requires:
|
||||
- setup
|
||||
- aio_monitoring_stable:
|
||||
requires:
|
||||
- setup
|
||||
- aio_monitoring_next:
|
||||
requires:
|
||||
- setup
|
||||
- saucelabs:
|
||||
# Testing saucelabs via Bazel currently taking longer than the legacy saucelabs job as it
|
||||
# each karma_web_test target is provisioning and tearing down browsers which is adding
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Image metadata and config.
|
||||
# Ideally, the Node.js version should match what we use on CI.
|
||||
# See `executors > default-executor` in `.circleci/config.yml`.
|
||||
FROM cimg/node:16.13-browsers
|
||||
FROM cimg/node:16.13-browsers@sha256:6c7a82701665dda03e92d682360fa2e4358e07dab8d1b6a7e48f7d36e3d98117
|
||||
|
||||
|
||||
LABEL name="Angular dev environment" \
|
||||
|
||||
@@ -4,7 +4,7 @@ description: 'Installs the dependencies using Yarn'
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3
|
||||
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3
|
||||
with:
|
||||
path: |
|
||||
./node_modules/
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
steps:
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3
|
||||
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
|
||||
|
||||
- name: Configure Firebase deploy target
|
||||
working-directory: aio/
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
saucelabs:
|
||||
runs-on: ubuntu-latest-4core
|
||||
env:
|
||||
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
|
||||
SAUCE_USERNAME: ${{ vars.SAUCE_USERNAME }}
|
||||
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@1befe6d24fd5cab818e7f8bada40ab364781b8a8
|
||||
with:
|
||||
cache-node-modules: true
|
||||
# Checking out the pull request commit is intended here as we need to run the changed code tests.
|
||||
ref: ${{ github.sha }}
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@1befe6d24fd5cab818e7f8bada40ab364781b8a8
|
||||
- name: Starting Saucelabs tunnel service
|
||||
run: ./tools/saucelabs/sauce-service.sh run &
|
||||
# Build test fixtures for a test that rely on Bazel-generated fixtures. Note that disabling
|
||||
# specific tests which are reliant on such generated fixtures is not an option as SystemJS
|
||||
# in the Saucelabs legacy job always fetches referenced files, even if the imports would be
|
||||
# guarded by an check to skip in the Saucelabs legacy job. We should be good running such
|
||||
# test in all supported browsers on Saucelabs anyway until this job can be removed.
|
||||
- name: Preparing Bazel-generated fixtures required in legacy tests
|
||||
run: |
|
||||
yarn bazel build //packages/core/test:downleveled_es5_fixture //packages/common/locales
|
||||
# Needed for the ES5 downlevel reflector test in `packages/core/test/reflection`.
|
||||
mkdir -p dist/legacy-test-out/core/test/reflection/
|
||||
cp dist/bin/packages/core/test/reflection/es5_downleveled_inheritance_fixture.js \
|
||||
dist/legacy-test-out/core/test/reflection/es5_downleveled_inheritance_fixture.js
|
||||
# Locale files are needed for i18n tests running within Saucelabs. These are added
|
||||
# directly as sources so that the TypeScript compilation of `/packages/tsconfig.json`
|
||||
# can succeed. Note that the base locale and currencies files are checked-in, so
|
||||
# we do not need to re-generate those through Bazel.
|
||||
mkdir -p packages/common/locales/extra
|
||||
cp dist/bin/packages/common/locales/*.ts packages/common/locales
|
||||
cp dist/bin/packages/common/locales/extra/*.ts packages/common/locales/extra
|
||||
- name: Build bundle of tests to run on Saucelabs
|
||||
run: node tools/legacy-saucelabs/build-saucelabs-test-bundle.mjs
|
||||
- name: Wait and confirm Saucelabs tunnel has connected
|
||||
run: ./tools/saucelabs/sauce-service.sh ready-wait
|
||||
timeout-minutes: 3
|
||||
- name: Running tests on Saucelabs.
|
||||
run: KARMA_WEB_TEST_MODE=SL_REQUIRED yarn karma start ./karma-js.conf.js --single-run
|
||||
- name: Stop Saucelabs tunnel service
|
||||
run: ./tools/saucelabs/sauce-service.sh stop
|
||||
@@ -89,3 +89,145 @@ jobs:
|
||||
run: yarn install --frozen-lockfile --network-timeout 100000
|
||||
- name: Test all windows CI targets
|
||||
run: bazel test --test_tag_filters="-browser:chromium-local" //packages/compiler-cli/...
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile --network-timeout 100000
|
||||
- name: Run CI tests for framework
|
||||
run: yarn test:ci
|
||||
|
||||
aio:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
- name: Install node modules for aio
|
||||
run: yarn install --cwd aio --frozen-lockfile
|
||||
- name: Run AIO tests with upstream packages
|
||||
run: yarn --cwd aio test:ci
|
||||
- name: Check generated bundle sizes
|
||||
run: yarn --cwd aio payload-size
|
||||
|
||||
aio-local:
|
||||
runs-on:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
- name: Install node modules
|
||||
run: yarn install --cwd aio --frozen-lockfile
|
||||
- name: Run AIO tests with local packages
|
||||
run: yarn --cwd aio test-local:ci
|
||||
- name: Check generated bundle sizes
|
||||
run: yarn --cwd aio payload-size aio-local
|
||||
|
||||
aio-deploy:
|
||||
needs: [aio]
|
||||
if: needs.aio.result == 'success' && github.event_name == 'push'
|
||||
runs-on:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
- name: Install node modules for aio
|
||||
run: yarn install --cwd aio --frozen-lockfile
|
||||
- name: Set the stable branch environment variable
|
||||
id: latest_version
|
||||
run: |
|
||||
echo "CI_STABLE_BRANCH=$(npm info @angular/core dist-tags.latest | sed -r 's/^\s*([0-9]+\.[0-9]+)\.[0-9]+.*$/\1.x/')" >> $GITHUB_OUTPUT
|
||||
echo "CI_BRANCH=$(echo ${{ github.event.ref }} | cut -d '/' -f 3)" >> $GITHUB_OUTPUT
|
||||
- name: Deploy aio to production
|
||||
env:
|
||||
CI_AIO_MIN_PWA_SCORE: '95'
|
||||
CI_COMMIT: ${{ github.event.after }}
|
||||
CI_REPO_NAME: 'angular'
|
||||
CI_PULL_REQUEST: 'false'
|
||||
CI_REPO_OWNER: 'angular'
|
||||
CI_BUILD_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||
CI_STABLE_BRANCH: ${{ steps.latest_version.outputs.CI_STABLE_BRANCH }}
|
||||
CI_BRANCH: ${{ steps.latest_version.outputs.CI_BRANCH }}
|
||||
CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN: ${{ secrets.AIO_DEPLOY_TOKEN }}
|
||||
CI_SECRET_PAYLOAD_FIREBASE_TOKEN: ${{ secrets.AIO_PAYLOAD_TOKEN }}
|
||||
run: yarn --cwd aio deploy-production
|
||||
|
||||
zone-js:
|
||||
runs-on:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./node_modules
|
||||
./packages/zone.js/node_modules
|
||||
./packages/zone.js/test/typings/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@45de46d9ba0e0689b7a846fd31ec9e241807ca71
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: |
|
||||
yarn bazel build \
|
||||
//packages/zone.js/bundles:zone.umd.js \
|
||||
//packages/zone.js:npm_package \
|
||||
//packages/zone.js/test/closure:closure_js \
|
||||
//packages/zone.js:zone_externs
|
||||
|
||||
- run: |
|
||||
mkdir -p packages/zone.js/build/
|
||||
mkdir -p packages/zone.js/build/test/
|
||||
mkdir -p packages/zone.js/test/
|
||||
|
||||
cp dist/bin/packages/zone.js/bundles/zone.umd.js packages/zone.js/build/zone.umd.js
|
||||
cp dist/bin/packages/zone.js/npm_package/bundles/zone-mix.umd.js ./packages/zone.js/test/extra/
|
||||
cp dist/bin/packages/zone.js/npm_package/bundles/zone-patch-electron.umd.js ./packages/zone.js/test/extra/
|
||||
cp dist/bin/packages/zone.js/test/closure/zone.closure.mjs ./packages/zone.js/build/test/zone.closure.mjs
|
||||
cp dist/bin/packages/zone.js/zone_externs.js ./packages/zone.js/build/zone_externs.js
|
||||
|
||||
# Install
|
||||
- run: yarn --cwd packages/zone.js install --frozen-lockfile --non-interactive
|
||||
# Run zone.js tools tests
|
||||
- run: yarn --cwd packages/zone.js promisetest
|
||||
- run: yarn --cwd packages/zone.js promisefinallytest
|
||||
- run: yarn --cwd packages/zone.js jest:test
|
||||
- run: yarn --cwd packages/zone.js jest:nodetest
|
||||
- run: yarn --cwd packages/zone.js electrontest
|
||||
- run: yarn --cwd packages/zone.js closuretest
|
||||
- run: yarn --cwd packages/zone.js/test/typings install --frozen-lockfile --non-interactive
|
||||
- run: yarn --cwd packages/zone.js/test/typings test
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
name: Monitoring
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run at 10:00AM every day.
|
||||
- cron: '0 10 * * *'
|
||||
|
||||
permissions: {}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
check_aio:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
MINIMUM_PWA_SCORE: 95
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version: ['https://next.angular.io/', 'https://angular.io/']
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0109d498b0f6aae418ed4924a5e5c65695f0ac61
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@0109d498b0f6aae418ed4924a5e5c65695f0ac61
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@0109d498b0f6aae418ed4924a5e5c65695f0ac61
|
||||
- name: Install node modules in aio
|
||||
run: yarn install --frozen-lockfile --cwd aio
|
||||
- name: Run basic e2e and deployment config tests.
|
||||
run: yarn --cwd aio test-production-url --test_env=TARGET_URL="${{ matrix.version }}"
|
||||
- name: Run PWA-score tests.
|
||||
run: yarn --cwd aio test-pwa-score "${{ matrix.version }}" "${{ env.MINIMUM_PWA_SCORE }}"
|
||||
- name: Run a11y tests.
|
||||
run: yarn --cwd aio test-a11y-score "${{ matrix.version }}"
|
||||
|
||||
check_contributor_links:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@0109d498b0f6aae418ed4924a5e5c65695f0ac61
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Install node modules in aio
|
||||
run: yarn install --frozen-lockfile --cwd aio
|
||||
- name: Check website provided in contributors.json file
|
||||
run: node aio/scripts/test-external-urls.js
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
|
||||
# Upload the results as artifacts.
|
||||
- name: 'Upload artifact'
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
@@ -47,6 +47,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: 'Upload to code-scanning'
|
||||
uses: github/codeql-action/upload-sarif@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 # v2.21.0
|
||||
uses: github/codeql-action/upload-sarif@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
+4
-4
@@ -57,9 +57,7 @@
|
||||
version: 3
|
||||
|
||||
availability:
|
||||
users_unavailable:
|
||||
- atscott
|
||||
- devversion
|
||||
users_unavailable: []
|
||||
|
||||
# Meta field that goes unused by PullApprove to allow for defining aliases to be
|
||||
# used throughout the config.
|
||||
@@ -339,7 +337,8 @@ groups:
|
||||
'aio/content/images/guide/view-encapsulation/**/{*,.*}',
|
||||
'aio/content/special-elements/**/{*,.*}',
|
||||
'aio/content/guide/hydration.md',
|
||||
'aio/content/guide/signals.md'
|
||||
'aio/content/guide/signals.md',
|
||||
'aio/content/examples/injection-token/**/{*,.*}',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
@@ -1124,6 +1123,7 @@ groups:
|
||||
users:
|
||||
- AleksanderBodurri
|
||||
- devversion
|
||||
- dgp1130
|
||||
- josephperrott
|
||||
- mgechev
|
||||
- twerske
|
||||
|
||||
+107
-89
@@ -1,3 +1,110 @@
|
||||
<a name="16.2.6"></a>
|
||||
# 16.2.6 (2023-09-20)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [82712f80df](https://github.com/angular/angular/commit/82712f80dfc6aed2baf8d8f80c3552a6707c88ff) | fix | ensure a consumer drops all its stale producers ([#51722](https://github.com/angular/angular/pull/51722)) ([#51772](https://github.com/angular/angular/pull/51772)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.5"></a>
|
||||
# 16.2.5 (2023-09-13)
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.4"></a>
|
||||
# 16.2.4 (2023-09-06)
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.3"></a>
|
||||
# 16.2.3 (2023-08-30)
|
||||
### animations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [04c6574280](https://github.com/angular/angular/commit/04c65742802537c8bd725f9a7a931955a67684d9) | fix | remove unnecessary escaping in regex expressions ([#51554](https://github.com/angular/angular/pull/51554)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [dbd761f528](https://github.com/angular/angular/commit/dbd761f528a08cba0fbdd476b115e1445683cf36) | fix | correct incomplete escaping ([#51557](https://github.com/angular/angular/pull/51557)) |
|
||||
| [5c36fc784f](https://github.com/angular/angular/commit/5c36fc784f292608f7485c5513aeb98e5745d17c) | fix | remove unnecessary escaping in regex expressions ([#51554](https://github.com/angular/angular/pull/51554)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [dcd1add06f](https://github.com/angular/angular/commit/dcd1add06f9facb87de89c144967cc95a2dac27c) | fix | correct incomplete escaping ([#51557](https://github.com/angular/angular/pull/51557)) |
|
||||
| [20d62603c2](https://github.com/angular/angular/commit/20d62603c2f86c810fda0b3b503327dce232a6d3) | fix | handle hydration of view containers that use component hosts as anchors ([#51456](https://github.com/angular/angular/pull/51456)) |
|
||||
| [e6b301caa2](https://github.com/angular/angular/commit/e6b301caa25c1532a4db2e8521bdea3f911316b1) | fix | remove unnecessary escaping in regex expressions ([#51554](https://github.com/angular/angular/pull/51554)) |
|
||||
| [0c7c852ee7](https://github.com/angular/angular/commit/0c7c852ee7ba3c1943cafce4c58760eef1b0aea4) | fix | run afterRender callbacks outside of the Angular zone ([#51551](https://github.com/angular/angular/pull/51551)) |
|
||||
### language-service
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8081fdd22d](https://github.com/angular/angular/commit/8081fdd22d6889f92e11cbe4c53d80bddd496a9a) | fix | correct incomplete escaping ([#51557](https://github.com/angular/angular/pull/51557)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.2"></a>
|
||||
# 16.2.2 (2023-08-23)
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [a43c0772ea](https://github.com/angular/angular/commit/a43c0772ea74410b0492a178c656268a465d3b09) | fix | Allow safeUrl for ngSrc in NgOptimizedImage ([#51351](https://github.com/angular/angular/pull/51351)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [39ace8664b](https://github.com/angular/angular/commit/39ace8664b843225a75dd706236ae13e171126d3) | fix | enforce a minimum version to be used when a library uses input transform ([#51413](https://github.com/angular/angular/pull/51413)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [36f434e49d](https://github.com/angular/angular/commit/36f434e49d24f0393950299486141a121d42e044) | fix | guard the jasmine hooks ([#51394](https://github.com/angular/angular/pull/51394)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b0396e7164](https://github.com/angular/angular/commit/b0396e7164c08e01d24d2d8411edf1ccf4b52826) | fix | Ensure `canceledNavigationResolution: 'computed'` works on first page ([#51441](https://github.com/angular/angular/pull/51441)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.1"></a>
|
||||
# 16.2.1 (2023-08-16)
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [232a8c1b8d](https://github.com/angular/angular/commit/232a8c1b8dadf3f886b4bd0142613d116c865759) | fix | Apply named outlets to children empty paths not appearing in the URL ([#51292](https://github.com/angular/angular/pull/51292)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.0"></a>
|
||||
# 16.2.0 (2023-08-09)
|
||||
### benchpress
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [dd850b2ab7](https://github.com/angular/angular/commit/dd850b2ab781f24065550f8a948ced498e0f1e99) | fix | correctly report GC memory amounts ([#50760](https://github.com/angular/angular/pull/50760)) |
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [29d358170b](https://github.com/angular/angular/commit/29d358170b046f4a6773dfdfbbd1050f54deb301) | feat | add component input binding support for NgComponentOutlet ([#51148](https://github.com/angular/angular/pull/51148)) |
|
||||
| [1837efb9da](https://github.com/angular/angular/commit/1837efb9daf5c8e86a99a06ecc77bb42bc60dbb0) | feat | Allow ngSrc to be changed post-init ([#50683](https://github.com/angular/angular/pull/50683)) |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c27a1e61d6](https://github.com/angular/angular/commit/c27a1e61d64a67aa169086f7db11bcfd5bb7d2fc) | feat | scope selectors in @scope queries ([#50747](https://github.com/angular/angular/pull/50747)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [12bad6576d](https://github.com/angular/angular/commit/12bad6576d2ffe4667118b214d9c7598ed3d8edb) | fix | libraries compiled with v16.1+ breaking with Angular framework v16.0.x ([#50714](https://github.com/angular/angular/pull/50714)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [e53d4ecf4c](https://github.com/angular/angular/commit/e53d4ecf4cfd9e64d6ba8c8b19adbb7df9cfc047) | feat | add afterRender and afterNextRender ([#50607](https://github.com/angular/angular/pull/50607)) |
|
||||
| [98d262fd27](https://github.com/angular/angular/commit/98d262fd27795014ee3988b08d3c48a0dfb63c40) | feat | create injector debugging APIs ([#48639](https://github.com/angular/angular/pull/48639)) |
|
||||
| [cdaa2a8a9e](https://github.com/angular/angular/commit/cdaa2a8a9eab490b55bbb841ede4f54a2656df30) | feat | support Provider type in Injector.create ([#49587](https://github.com/angular/angular/pull/49587)) |
|
||||
| [9f490da7e2](https://github.com/angular/angular/commit/9f490da7e27e495cb45d2064af9091731422a6b1) | fix | handle hydration of view containers for root components ([#51247](https://github.com/angular/angular/pull/51247)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [0b14e4ef74](https://github.com/angular/angular/commit/0b14e4ef742b1c0f73d873e2c337683b60f46845) | feat | exposes the `fixture` of the `RouterTestingHarness` ([#50280](https://github.com/angular/angular/pull/50280)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.1.8"></a>
|
||||
# 16.1.8 (2023-08-02)
|
||||
### compiler
|
||||
@@ -7,19 +114,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.0-next.4"></a>
|
||||
# 16.2.0-next.4 (2023-07-26)
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [29d358170b](https://github.com/angular/angular/commit/29d358170b046f4a6773dfdfbbd1050f54deb301) | feat | add component input binding support for NgComponentOutlet ([#51148](https://github.com/angular/angular/pull/51148)) |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [57e8412e53](https://github.com/angular/angular/commit/57e8412e53229b0671df02c55be52e88b66a6865) | fix | check whether `Zone` is defined ([#51119](https://github.com/angular/angular/pull/51119)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.1.7"></a>
|
||||
# 16.1.7 (2023-07-26)
|
||||
### http
|
||||
@@ -29,15 +123,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.0-next.3"></a>
|
||||
# 16.2.0-next.3 (2023-07-19)
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c5608e5ca9](https://github.com/angular/angular/commit/c5608e5ca99805af1a3a7caf4ce28a35f3a13ebf) | fix | Run fetch request out the angular zone ([#50981](https://github.com/angular/angular/pull/50981)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.1.6"></a>
|
||||
# 16.1.6 (2023-07-19)
|
||||
### http
|
||||
@@ -47,38 +132,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.0-next.2"></a>
|
||||
# 16.2.0-next.2 (2023-07-13)
|
||||
### animations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [a14bdfe859](https://github.com/angular/angular/commit/a14bdfe8591a33d359bf4940f4efa828499a6373) | fix | Ensure elements are removed from the cache after leave animation. ([#50929](https://github.com/angular/angular/pull/50929)) |
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [1837efb9da](https://github.com/angular/angular/commit/1837efb9daf5c8e86a99a06ecc77bb42bc60dbb0) | feat | Allow ngSrc to be changed post-init ([#50683](https://github.com/angular/angular/pull/50683)) |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c27a1e61d6](https://github.com/angular/angular/commit/c27a1e61d64a67aa169086f7db11bcfd5bb7d2fc) | feat | scope selectors in @scope queries ([#50747](https://github.com/angular/angular/pull/50747)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [031b599a55](https://github.com/angular/angular/commit/031b599a5528e1df5779695eb75b738a5a3076fe) | fix | ensure that standalone components get correct injector instances ([#50954](https://github.com/angular/angular/pull/50954)) |
|
||||
| [5d6ec0336b](https://github.com/angular/angular/commit/5d6ec0336bdea22735d0ca2bbd7cfad958efbdda) | fix | handle `deref` returning `null` on `RefactiveNode`. ([#50992](https://github.com/angular/angular/pull/50992)) |
|
||||
| [b66a16ec4c](https://github.com/angular/angular/commit/b66a16ec4cf42f47efeafa711ec301efeda272be) | fix | use `setTimeout` when coalescing tasks in Node.js ([#50820](https://github.com/angular/angular/pull/50820)) |
|
||||
### platform-browser
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [f1b629961f](https://github.com/angular/angular/commit/f1b629961f75d535982a6196e70b82f177587ebf) | perf | do not remove renderer from cache when `REMOVE_STYLES_ON_COMPONENT_DESTROY` is enabled. ([#51005](https://github.com/angular/angular/pull/51005)) |
|
||||
### upgrade
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [a19a87df6c](https://github.com/angular/angular/commit/a19a87df6c30a60ca997083b979a8e1e185e5b43) | fix | allow for downgraded components to work with component-router ([#50871](https://github.com/angular/angular/pull/50871)) |
|
||||
| [253d756464](https://github.com/angular/angular/commit/253d7564647607804d45404152d1253993177aea) | fix | Use `takeUntil` on leaky subscription. ([#50901](https://github.com/angular/angular/pull/50901)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.1.5"></a>
|
||||
# 16.1.5 (2023-07-13)
|
||||
### animations
|
||||
@@ -114,28 +167,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.0-next.1"></a>
|
||||
# 16.2.0-next.1 (2023-06-28)
|
||||
### benchpress
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [dd850b2ab7](https://github.com/angular/angular/commit/dd850b2ab781f24065550f8a948ced498e0f1e99) | fix | correctly report GC memory amounts ([#50760](https://github.com/angular/angular/pull/50760)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [29340a0678](https://github.com/angular/angular/commit/29340a06789652e359e61b32f1814dcd20d9bd26) | fix | expose input transform function on ComponentFactory and ComponentMirror ([#50713](https://github.com/angular/angular/pull/50713)) |
|
||||
### elements
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [d64864e95e](https://github.com/angular/angular/commit/d64864e95e193e46180aeaf0d634152327650871) | fix | support input transform functions ([#50713](https://github.com/angular/angular/pull/50713)) |
|
||||
### platform-browser
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [2b55103e94](https://github.com/angular/angular/commit/2b55103e94578ab1cb765147077e82e1228b0dbb) | fix | wait until animation completion before destroying renderer ([#50677](https://github.com/angular/angular/pull/50677)) |
|
||||
| [0380564f85](https://github.com/angular/angular/commit/0380564f8562f5971cff671319439ad0f2b40a7e) | fix | wait until animation completion before destroying renderer ([#50860](https://github.com/angular/angular/pull/50860)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.1.3"></a>
|
||||
# 16.1.3 (2023-06-28)
|
||||
### core
|
||||
@@ -154,19 +185,6 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.2.0-next.0"></a>
|
||||
# 16.2.0-next.0 (2023-06-21)
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [12bad6576d](https://github.com/angular/angular/commit/12bad6576d2ffe4667118b214d9c7598ed3d8edb) | fix | libraries compiled with v16.1+ breaking with Angular framework v16.0.x ([#50714](https://github.com/angular/angular/pull/50714)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [0b14e4ef74](https://github.com/angular/angular/commit/0b14e4ef742b1c0f73d873e2c337683b60f46845) | feat | exposes the `fixture` of the `RouterTestingHarness` ([#50280](https://github.com/angular/angular/pull/50280)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="16.1.2"></a>
|
||||
# 16.1.2 (2023-06-21)
|
||||
### http
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
```shell
|
||||
git commit --all
|
||||
```
|
||||
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
||||
Note: the optional commit `--all` command line option will automatically "add" and "rm" edited files.
|
||||
|
||||
10. Push your branch to GitHub:
|
||||
|
||||
|
||||
@@ -64,12 +64,7 @@ load("@rules_nodejs//nodejs:repositories.bzl", "nodejs_register_toolchains")
|
||||
|
||||
nodejs_register_toolchains(
|
||||
name = "nodejs",
|
||||
node_version = "16.14.0",
|
||||
)
|
||||
|
||||
nodejs_register_toolchains(
|
||||
name = "node18",
|
||||
node_version = "18.10.0",
|
||||
node_version = "18.13.0",
|
||||
)
|
||||
|
||||
# Download npm dependencies.
|
||||
@@ -199,10 +194,10 @@ cldr_xml_data_repository(
|
||||
# sass rules
|
||||
http_archive(
|
||||
name = "io_bazel_rules_sass",
|
||||
sha256 = "be45350fce6cec8c6bf98238d51ec270b58b1a93ace6acf156ab0b09bbccaaf9",
|
||||
strip_prefix = "rules_sass-ded821e3fc30ec3ceecdc28618b8b5df440a26be",
|
||||
sha256 = "81758d485da797baca81fb07e2b14a818e33c539beaddeb373054b5c39807010",
|
||||
strip_prefix = "rules_sass-63d77ffdf3039aae1f0bb54e05ff47b7c50f1553",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/rules_sass/archive/ded821e3fc30ec3ceecdc28618b8b5df440a26be.zip",
|
||||
"https://github.com/bazelbuild/rules_sass/archive/63d77ffdf3039aae1f0bb54e05ff47b7c50f1553.zip",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"branchName": "refs/heads/main",
|
||||
"sha": "d29cbad7e25ed9114be351b9582eb8723db14773"
|
||||
"branchName": "refs/heads/16.2.x",
|
||||
"sha": "99ff60cdfe5ca0a8b9ad6bf77ac60a929a27de38"
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
"command": "ng build [project]",
|
||||
"shortDescription": "Compiles an Angular application or library into an output directory named dist/ at the given output path.",
|
||||
"longDescriptionRelativePath": "@angular/cli/src/commands/build/long-description.md",
|
||||
"longDescription": "The command can be used to build a project of type \"application\" or \"library\".\nWhen used to build a library, a different builder is invoked, and only the `ts-config`, `configuration`, and `watch` options are applied.\nAll other options apply only to building applications.\n\nThe application builder uses the [webpack](https://webpack.js.org/) build tool, with default configuration options specified in the workspace configuration file (`angular.json`) or with a named alternative configuration.\nA \"development\" configuration is created by default when you use the CLI to create the project, and you can use that configuration by specifying the `--configuration development`.\n\nThe configuration options generally correspond to the command options.\nYou can override individual configuration defaults by specifying the corresponding options on the command line.\nThe command can accept option names given in either dash-case or camelCase.\nNote that in the configuration file, you must specify names in camelCase.\n\nSome additional options can only be set through the configuration file,\neither by direct editing or with the `ng config` command.\nThese include `assets`, `styles`, and `scripts` objects that provide runtime-global resources to include in the project.\nResources in CSS, such as images and fonts, are automatically written and fingerprinted at the root of the output folder.\n\nFor further details, see [Workspace Configuration](guide/workspace-config).\n",
|
||||
"longDescription": "The command can be used to build a project of type \"application\" or \"library\".\nWhen used to build a library, a different builder is invoked, and only the `ts-config`, `configuration`, and `watch` options are applied.\nAll other options apply only to building applications.\n\nThe application builder uses the [webpack](https://webpack.js.org/) build tool, with default configuration options specified in the workspace configuration file (`angular.json`) or with a named alternative configuration.\nA \"development\" configuration is created by default when you use the CLI to create the project, and you can use that configuration by specifying the `--configuration development`.\n\nThe configuration options generally correspond to the command options.\nYou can override individual configuration defaults by specifying the corresponding options on the command line.\nThe command can accept option names given in dash-case.\nNote that in the configuration file, you must specify names in camelCase.\n\nSome additional options can only be set through the configuration file,\neither by direct editing or with the `ng config` command.\nThese include `assets`, `styles`, and `scripts` objects that provide runtime-global resources to include in the project.\nResources in CSS, such as images and fonts, are automatically written and fingerprinted at the root of the output folder.\n\nFor further details, see [Workspace Configuration](guide/workspace-config).\n",
|
||||
"aliases": [
|
||||
"b"
|
||||
],
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
"positional": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Your first Angular app</title>
|
||||
</head>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
@name HTML content was altered after server-side rendering
|
||||
@category runtime
|
||||
@shortDescription HTML content was altered after server-side rendering
|
||||
|
||||
@description
|
||||
Angular throws this error when it detects that the content generated by server-side rendering (SSR) was altered after the rendering. The process of hydration relies on the content to be untouched after SSR, which also includes whitespaces and comment nodes. Those whitespaces and comment nodes must be retained in the HTML generated by the SSR process. Learn more in the [Hydration guide](guide/hydration#constraints).
|
||||
|
||||
@debugging
|
||||
|
||||
Typically this happens in the following cases:
|
||||
* Some CDN providers have a built-in feature to remove whitespaces and comment nodes from HTML as an optimization. Please verify if there is such an option in CDN configuration and turn it off.
|
||||
* If you use custom post-processing of HTML generated by SSR (as a build step), make sure that this process doesn't remove whitespaces and comment nodes.
|
||||
Regular → Executable
Regular → Executable
+1
@@ -1,6 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-about',
|
||||
templateUrl: './about.component.html',
|
||||
styleUrls: ['./about.component.css']
|
||||
|
||||
Regular → Executable
+10
-10
@@ -31,15 +31,15 @@ export const slideInAnimation =
|
||||
// #docregion query
|
||||
query(':enter', [
|
||||
style({ left: '-100%' })
|
||||
]),
|
||||
query(':leave', animateChild()),
|
||||
], { optional: true }),
|
||||
query(':leave', animateChild(), { optional: true }),
|
||||
group([
|
||||
query(':leave', [
|
||||
animate('300ms ease-out', style({ left: '100%' }))
|
||||
]),
|
||||
], { optional: true }),
|
||||
query(':enter', [
|
||||
animate('300ms ease-out', style({ left: '0%' }))
|
||||
]),
|
||||
], { optional: true }),
|
||||
]),
|
||||
]),
|
||||
transition('* <=> *', [
|
||||
@@ -51,19 +51,19 @@ export const slideInAnimation =
|
||||
left: 0,
|
||||
width: '100%'
|
||||
})
|
||||
]),
|
||||
], { optional: true }),
|
||||
query(':enter', [
|
||||
style({ left: '-100%' })
|
||||
]),
|
||||
query(':leave', animateChild()),
|
||||
], { optional: true }),
|
||||
query(':leave', animateChild(), { optional: true }),
|
||||
group([
|
||||
query(':leave', [
|
||||
animate('200ms ease-out', style({ left: '100%', opacity: 0 }))
|
||||
]),
|
||||
], { optional: true }),
|
||||
query(':enter', [
|
||||
animate('300ms ease-out', style({ left: '0%' }))
|
||||
]),
|
||||
query('@*', animateChild())
|
||||
], { optional: true }),
|
||||
query('@*', animateChild(), { optional: true })
|
||||
]),
|
||||
])
|
||||
// #enddocregion query
|
||||
|
||||
Regular → Executable
+1
@@ -2,6 +2,7 @@
|
||||
import { Component, HostBinding } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-root',
|
||||
templateUrl: 'app.component.html',
|
||||
styleUrls: ['app.component.css'],
|
||||
|
||||
Regular → Executable
+3
-1
@@ -11,14 +11,16 @@ import {
|
||||
} from '@angular/animations';
|
||||
|
||||
// #enddocregion imports
|
||||
import { ChildrenOutletContexts, RouterOutlet } from '@angular/router';
|
||||
import { ChildrenOutletContexts, RouterLink, RouterOutlet } from '@angular/router';
|
||||
import { slideInAnimation } from './animations';
|
||||
|
||||
// #docregion decorator, toggle-app-animations, define
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-root',
|
||||
templateUrl: 'app.component.html',
|
||||
styleUrls: ['app.component.css'],
|
||||
imports: [RouterLink, RouterOutlet],
|
||||
animations: [
|
||||
// #enddocregion decorator
|
||||
slideInAnimation
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { ApplicationConfig } from '@angular/core';
|
||||
import { routes } from './app.routes';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { provideProtractorTestingSupport } from '@angular/platform-browser';
|
||||
import { provideAnimations } from '@angular/platform-browser/animations';
|
||||
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
// needed for supporting e2e tests
|
||||
provideProtractorTestingSupport(),
|
||||
provideRouter(routes),
|
||||
provideAnimations(),
|
||||
]
|
||||
};
|
||||
+31
-70
@@ -1,112 +1,73 @@
|
||||
// #docregion route-animation-data
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { AppComponent } from './app.component';
|
||||
import { OpenCloseComponent } from './open-close.component';
|
||||
import { Routes } from '@angular/router';
|
||||
import { OpenClosePageComponent } from './open-close-page.component';
|
||||
import { OpenCloseChildComponent } from './open-close.component.4';
|
||||
import { ToggleAnimationsPageComponent } from './toggle-animations-page.component';
|
||||
import { StatusSliderComponent } from './status-slider.component';
|
||||
import { StatusSliderPageComponent } from './status-slider-page.component';
|
||||
import { ToggleAnimationsPageComponent } from './toggle-animations-page.component';
|
||||
import { HeroListPageComponent } from './hero-list-page.component';
|
||||
import { HeroListGroupPageComponent } from './hero-list-group-page.component';
|
||||
import { HeroListGroupsComponent } from './hero-list-groups.component';
|
||||
import { HeroListEnterLeavePageComponent } from './hero-list-enter-leave-page.component';
|
||||
import { HeroListEnterLeaveComponent } from './hero-list-enter-leave.component';
|
||||
import { HeroListAutoCalcPageComponent } from './hero-list-auto-page.component';
|
||||
import { HeroListAutoComponent } from './hero-list-auto.component';
|
||||
import { HomeComponent } from './home.component';
|
||||
import { AboutComponent } from './about.component';
|
||||
import { InsertRemoveComponent } from './insert-remove.component';
|
||||
import { QueryingComponent } from './querying.component';
|
||||
import { HomeComponent } from './home.component';
|
||||
import { AboutComponent } from './about.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
RouterModule.forRoot([
|
||||
{ path: '', pathMatch: 'full', redirectTo: '/enter-leave' },
|
||||
{
|
||||
// #docregion route-animation-data
|
||||
export const routes: Routes = [
|
||||
{ path: '', pathMatch: 'full', redirectTo: '/enter-leave' },
|
||||
{
|
||||
path: 'open-close',
|
||||
component: OpenClosePageComponent,
|
||||
data: { animation: 'openClosePage' }
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
path: 'status',
|
||||
component: StatusSliderPageComponent,
|
||||
data: { animation: 'statusPage' }
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
path: 'toggle',
|
||||
component: ToggleAnimationsPageComponent,
|
||||
data: { animation: 'togglePage' }
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
path: 'heroes',
|
||||
component: HeroListPageComponent,
|
||||
data: { animation: 'filterPage' }
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
path: 'hero-groups',
|
||||
component: HeroListGroupPageComponent,
|
||||
data: { animation: 'heroGroupPage' }
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
path: 'enter-leave',
|
||||
component: HeroListEnterLeavePageComponent,
|
||||
data: { animation: 'enterLeavePage' }
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
path: 'auto',
|
||||
component: HeroListAutoCalcPageComponent,
|
||||
data: { animation: 'autoPage' }
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
path: 'insert-remove',
|
||||
component: InsertRemoveComponent,
|
||||
data: { animation: 'insertRemovePage' }
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
path: 'querying',
|
||||
component: QueryingComponent,
|
||||
data: { animation: 'queryingPage' }
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
path: 'home',
|
||||
component: HomeComponent,
|
||||
data: { animation: 'HomePage' }
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
path: 'about',
|
||||
component: AboutComponent,
|
||||
data: { animation: 'AboutPage' }
|
||||
},
|
||||
])
|
||||
],
|
||||
// #enddocregion route-animation-data
|
||||
declarations: [
|
||||
AppComponent,
|
||||
StatusSliderComponent,
|
||||
OpenCloseComponent,
|
||||
OpenCloseChildComponent,
|
||||
OpenClosePageComponent,
|
||||
StatusSliderPageComponent,
|
||||
ToggleAnimationsPageComponent,
|
||||
HeroListPageComponent,
|
||||
HeroListGroupsComponent,
|
||||
HeroListGroupPageComponent,
|
||||
HeroListEnterLeavePageComponent,
|
||||
HeroListEnterLeaveComponent,
|
||||
HeroListAutoCalcPageComponent,
|
||||
HeroListAutoComponent,
|
||||
HomeComponent,
|
||||
InsertRemoveComponent,
|
||||
QueryingComponent,
|
||||
AboutComponent
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
},
|
||||
];
|
||||
// #enddocregion route-animation-data
|
||||
Regular → Executable
+4
-1
@@ -1,7 +1,9 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { HEROES } from './mock-heroes';
|
||||
import { HeroListAutoComponent } from './hero-list-auto.component';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-hero-list-auto-page',
|
||||
template: `
|
||||
<section>
|
||||
@@ -9,7 +11,8 @@ import { HEROES } from './mock-heroes';
|
||||
|
||||
<app-hero-list-auto [heroes]="heroes" (remove)="onRemove($event)"></app-hero-list-auto>
|
||||
</section>
|
||||
`
|
||||
`,
|
||||
imports: [HeroListAutoComponent]
|
||||
})
|
||||
export class HeroListAutoCalcPageComponent {
|
||||
heroes = HEROES.slice();
|
||||
|
||||
Regular → Executable
+3
@@ -13,11 +13,14 @@ import {
|
||||
} from '@angular/animations';
|
||||
|
||||
import { Hero } from './hero';
|
||||
import { NgFor } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-hero-list-auto',
|
||||
templateUrl: 'hero-list-auto.component.html',
|
||||
styleUrls: ['./hero-list-page.component.css'],
|
||||
imports: [NgFor],
|
||||
// #docregion auto-calc
|
||||
animations: [
|
||||
trigger('shrinkOut', [
|
||||
|
||||
Regular → Executable
+4
-1
@@ -1,7 +1,9 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { HEROES } from './mock-heroes';
|
||||
import { HeroListEnterLeaveComponent } from './hero-list-enter-leave.component';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-hero-list-enter-leave-page',
|
||||
template: `
|
||||
<section>
|
||||
@@ -9,7 +11,8 @@ import { HEROES } from './mock-heroes';
|
||||
|
||||
<app-hero-list-enter-leave [heroes]="heroes" (remove)="onRemove($event)"></app-hero-list-enter-leave>
|
||||
</section>
|
||||
`
|
||||
`,
|
||||
imports: [HeroListEnterLeaveComponent]
|
||||
})
|
||||
export class HeroListEnterLeavePageComponent {
|
||||
heroes = HEROES.slice();
|
||||
|
||||
Regular → Executable
+3
@@ -13,8 +13,10 @@ import {
|
||||
} from '@angular/animations';
|
||||
|
||||
import { Hero } from './hero';
|
||||
import { NgFor } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-hero-list-enter-leave',
|
||||
template: `
|
||||
<ul class="heroes">
|
||||
@@ -28,6 +30,7 @@ import { Hero } from './hero';
|
||||
</ul>
|
||||
`,
|
||||
styleUrls: ['./hero-list-page.component.css'],
|
||||
imports: [NgFor],
|
||||
// #docregion animationdef
|
||||
animations: [
|
||||
trigger('flyInOut', [
|
||||
|
||||
Regular → Executable
+4
-1
@@ -1,7 +1,9 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { HEROES } from './mock-heroes';
|
||||
import { HeroListGroupsComponent } from './hero-list-groups.component';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-hero-list-groups-page',
|
||||
template: `
|
||||
<section>
|
||||
@@ -9,7 +11,8 @@ import { HEROES } from './mock-heroes';
|
||||
|
||||
<app-hero-list-groups [heroes]="heroes" (remove)="onRemove($event)"></app-hero-list-groups>
|
||||
</section>
|
||||
`
|
||||
`,
|
||||
imports: [HeroListGroupsComponent]
|
||||
})
|
||||
export class HeroListGroupPageComponent {
|
||||
heroes = HEROES.slice();
|
||||
|
||||
Regular → Executable
+3
@@ -14,8 +14,10 @@ import {
|
||||
} from '@angular/animations';
|
||||
|
||||
import { Hero } from './hero';
|
||||
import { NgFor } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-hero-list-groups',
|
||||
template: `
|
||||
<ul class="heroes">
|
||||
@@ -28,6 +30,7 @@ import { Hero } from './hero';
|
||||
</ul>
|
||||
`,
|
||||
styleUrls: ['./hero-list-page.component.css'],
|
||||
imports: [NgFor],
|
||||
// #docregion animationdef
|
||||
animations: [
|
||||
trigger('flyInOut', [
|
||||
|
||||
Regular → Executable
+3
@@ -4,10 +4,13 @@ import { Component, HostBinding, OnInit } from '@angular/core';
|
||||
import { trigger, transition, animate, style, query, stagger } from '@angular/animations';
|
||||
import { HEROES } from './mock-heroes';
|
||||
import { Hero } from './hero';
|
||||
import { NgFor } from '@angular/common';
|
||||
|
||||
// #docregion filter-animations
|
||||
@Component({
|
||||
// #enddocregion filter-animations
|
||||
standalone: true,
|
||||
imports: [NgFor],
|
||||
selector: 'app-hero-list-page',
|
||||
templateUrl: 'hero-list-page.component.html',
|
||||
styleUrls: ['hero-list-page.component.css'],
|
||||
|
||||
Regular → Executable
+1
@@ -1,6 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.css']
|
||||
|
||||
Regular → Executable
+3
@@ -1,9 +1,12 @@
|
||||
// #docplaster
|
||||
import { Component } from '@angular/core';
|
||||
import { trigger, transition, animate, style } from '@angular/animations';
|
||||
import { NgIf } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-insert-remove',
|
||||
imports: [NgIf],
|
||||
animations: [
|
||||
// #docregion enter-leave-trigger
|
||||
trigger('myInsertRemoveTrigger', [
|
||||
|
||||
Regular → Executable
+4
-1
@@ -1,6 +1,8 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { OpenCloseComponent } from './open-close.component';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-open-close-page',
|
||||
template: `
|
||||
<section>
|
||||
@@ -10,7 +12,8 @@ import { Component } from '@angular/core';
|
||||
|
||||
<app-open-close [logging]="logging"></app-open-close>
|
||||
</section>
|
||||
`
|
||||
`,
|
||||
imports: [OpenCloseComponent]
|
||||
})
|
||||
export class OpenClosePageComponent {
|
||||
logging = false;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Component } from '@angular/core';
|
||||
import { trigger, transition, state, animate, style, keyframes } from '@angular/animations';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-open-close',
|
||||
animations: [
|
||||
// #docregion trigger
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Component } from '@angular/core';
|
||||
import { trigger, transition, state, animate, style } from '@angular/animations';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-open-close-boolean',
|
||||
// #docregion trigger-boolean
|
||||
animations: [
|
||||
|
||||
Regular → Executable
+1
@@ -5,6 +5,7 @@ import { transition, trigger, useAnimation } from '@angular/animations';
|
||||
import { transitionAnimation } from './animations';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-open-close-reusable',
|
||||
animations: [
|
||||
trigger('openClose', [
|
||||
|
||||
Regular → Executable
+1
@@ -6,6 +6,7 @@ import { trigger, transition, state, animate, style } from '@angular/animations'
|
||||
// #docregion toggle-animation
|
||||
@Component({
|
||||
// #enddocregion toggle-animation
|
||||
standalone: true,
|
||||
selector: 'app-open-close-toggle',
|
||||
templateUrl: 'open-close.component.4.html',
|
||||
styleUrls: ['open-close.component.css'],
|
||||
|
||||
Regular → Executable
+1
@@ -4,6 +4,7 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
|
||||
|
||||
// #docregion component, events1
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-open-close',
|
||||
// #docregion trigger-wildcard1, trigger-transition
|
||||
animations: [
|
||||
|
||||
Regular → Executable
+3
@@ -13,8 +13,10 @@ import {
|
||||
} from '@angular/animations';
|
||||
|
||||
import { HEROES } from './mock-heroes';
|
||||
import { NgIf } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-querying',
|
||||
template: `
|
||||
<nav>
|
||||
@@ -31,6 +33,7 @@ import { HEROES } from './mock-heroes';
|
||||
</section>
|
||||
`,
|
||||
styleUrls: ['./querying.component.css'],
|
||||
imports: [NgIf],
|
||||
animations: [
|
||||
trigger('query', [
|
||||
transition(':enter', [
|
||||
|
||||
Regular → Executable
+4
-1
@@ -1,12 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { StatusSliderComponent } from './status-slider.component';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-status-slider-page',
|
||||
template: `
|
||||
<section>
|
||||
<h2>Status Slider</h2>
|
||||
<app-status-slider></app-status-slider>
|
||||
</section>
|
||||
`
|
||||
`,
|
||||
imports: [StatusSliderComponent]
|
||||
})
|
||||
export class StatusSliderPageComponent {}
|
||||
|
||||
Regular → Executable
+1
@@ -2,6 +2,7 @@ import { Component } from '@angular/core';
|
||||
import { trigger, transition, state, animate, style, keyframes } from '@angular/animations';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-status-slider',
|
||||
templateUrl: 'status-slider.component.html',
|
||||
styleUrls: ['status-slider.component.css'],
|
||||
|
||||
Regular → Executable
+4
-1
@@ -1,6 +1,8 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { OpenCloseChildComponent } from './open-close.component.4';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-toggle-animations-child-page',
|
||||
template: `
|
||||
<section>
|
||||
@@ -8,6 +10,7 @@ import { Component } from '@angular/core';
|
||||
|
||||
<app-open-close-toggle></app-open-close-toggle>
|
||||
</section>
|
||||
`
|
||||
`,
|
||||
imports: [OpenCloseChildComponent]
|
||||
})
|
||||
export class ToggleAnimationsPageComponent {}
|
||||
|
||||
Regular → Executable
+4
-5
@@ -1,6 +1,5 @@
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { AppComponent } from './app/app.component';
|
||||
import { appConfig } from './app/app.config';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
bootstrapApplication(AppComponent, appConfig);
|
||||
|
||||
@@ -7,22 +7,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { SubmitButtonComponent } from './submit-button/submit-button.component';
|
||||
|
||||
// #docregion lazyload-syntax, lazyload-deprecated-syntax
|
||||
const routes: Routes = [{
|
||||
path: 'lazy',
|
||||
// #enddocregion lazyload-deprecated-syntax
|
||||
// The new import() syntax
|
||||
loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule)
|
||||
// #enddocregion lazyload-syntax
|
||||
/*
|
||||
// #docregion lazyload-deprecated-syntax
|
||||
// The following string syntax for loadChildren is deprecated
|
||||
loadChildren: './lazy/lazy.module#LazyModule',
|
||||
// #enddocregion lazyload-deprecated-syntax
|
||||
*/
|
||||
// #docregion lazyload-syntax, lazyload-deprecated-syntax
|
||||
}];
|
||||
// #enddocregion lazyload-syntax, lazyload-deprecated-syntax
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
@@ -31,7 +15,6 @@ const routes: Routes = [{
|
||||
// #docregion reactive-form-no-warning
|
||||
imports: [
|
||||
// #enddocregion reactive-form-no-warning
|
||||
RouterModule.forChild(routes),
|
||||
FormsModule,
|
||||
BrowserModule,
|
||||
// #docregion reactive-form-no-warning
|
||||
|
||||
@@ -67,6 +67,7 @@ EXAMPLES = {
|
||||
"http": {"stackblitz": True, "zip": True},
|
||||
"i18n": {"stackblitz": True, "zip": True},
|
||||
"inputs-outputs": {"stackblitz": True, "zip": True},
|
||||
"injection-token": {"stackblitz": False, "zip": False},
|
||||
"interpolation": {"stackblitz": True, "zip": True},
|
||||
"lazy-loading-ngmodules": {"stackblitz": True, "zip": True},
|
||||
"lifecycle-hooks": {"stackblitz": True, "zip": True},
|
||||
@@ -131,7 +132,6 @@ def docs_example(name, test = True, test_tags = [], test_exec_properties = {}, f
|
||||
native.filegroup(
|
||||
name = "files",
|
||||
srcs = native.glob(["**"], exclude = [
|
||||
"BUILD.bazel",
|
||||
"**/node_modules/**", # Node modules may exist from the legacy setup.
|
||||
]),
|
||||
)
|
||||
|
||||
+4
@@ -1,18 +1,22 @@
|
||||
<div class="tax-return">
|
||||
<div class="msg" [class.canceled]="message==='Canceled'">{{message}}</div>
|
||||
<fieldset>
|
||||
<legend>Tax Return</legend>
|
||||
<span id=name>{{taxReturn.name}}</span>
|
||||
<span id=tid>TID: {{taxReturn.tid}}</span>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Tax Return</legend>
|
||||
<label for="income">
|
||||
Income: <input id="income" [(ngModel)]="taxReturn.income" class="num">
|
||||
</label>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Tax Return</legend>
|
||||
<span>Tax: {{taxReturn.tax}}</span>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Tax Return</legend>
|
||||
<button type="button" (click)="onSaved()">Save</button>
|
||||
<button type="button" (click)="onCanceled()">Cancel</button>
|
||||
<button type="button" (click)="onClose()">Close</button>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
load("//aio/content/examples:examples.bzl", "docs_example")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
docs_example(
|
||||
name = "injection-token",
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* This example project is special in that it is not a cli app. To run tests appropriate for this
|
||||
* project, the test command is overwritten in `aio/content/examples/injection-token/example-config.json`.
|
||||
*
|
||||
* This is an empty placeholder file to ensure that `aio/tools/examples/run-example-e2e.mjs` runs
|
||||
* tests for this project.
|
||||
*
|
||||
* TODO: Fix our infrastructure/tooling, so that this hack is not necessary.
|
||||
*/
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"tests": [
|
||||
{
|
||||
"cmd": "yarn",
|
||||
"args": [ "tsc", "--project", "./tsconfig.app.json" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// TODO: Add unit tests for this file.
|
||||
/* eslint-disable @angular-eslint/no-output-native */
|
||||
// #docregion
|
||||
import {Injector, InjectionToken} from '@angular/core';
|
||||
|
||||
interface MyInterface {
|
||||
someProperty: string;
|
||||
}
|
||||
|
||||
// #docregion InjectionToken
|
||||
|
||||
const TOKEN = new InjectionToken<MyInterface>('SomeToken');
|
||||
|
||||
// Setting up the provider using the same token instance
|
||||
const providers = [
|
||||
{provide: TOKEN, useValue: {someProperty: 'exampleValue'}}, // Mock value for MyInterface
|
||||
];
|
||||
|
||||
// Creating the injector with the provider
|
||||
const injector = Injector.create({providers});
|
||||
|
||||
// Retrieving the value using the same token instance
|
||||
const myInterface = injector.get(TOKEN);
|
||||
// myInterface is inferred to be MyInterface.
|
||||
|
||||
// #enddocregion InjectionToken
|
||||
@@ -1,6 +1,6 @@
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-compose-message',
|
||||
@@ -12,7 +12,7 @@ export class ComposeMessageComponent {
|
||||
message = '';
|
||||
sending = false;
|
||||
|
||||
constructor(private router: Router) {}
|
||||
constructor(private router: Router, private route: ActivatedRoute) {}
|
||||
|
||||
send() {
|
||||
this.sending = true;
|
||||
@@ -32,7 +32,7 @@ export class ComposeMessageComponent {
|
||||
closePopup() {
|
||||
// Providing a `null` value to the named outlet
|
||||
// clears the contents of the named outlet
|
||||
this.router.navigate([{ outlets: { popup: null }}]);
|
||||
this.router.navigate([{outlets: {popup: null}}], {relativeTo: this.route.parent});
|
||||
}
|
||||
// #enddocregion closePopup
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base href="/">
|
||||
<title>Angular App</title>
|
||||
@@ -6,4 +7,4 @@
|
||||
<body>
|
||||
<app-root>loading</app-root>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -30,6 +30,6 @@ describe('Security E2E Tests', () => {
|
||||
|
||||
it('binds trusted resource URLs', async () => {
|
||||
const iframe = element(By.className('e2e-iframe-trusted-src'));
|
||||
expect(await iframe.getAttribute('src')).toMatch(/^https:\/\/www.youtube.com\//);
|
||||
expect(await iframe.getAttribute('src')).toMatch(/^https:\/\/www\.youtube\.com\//);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -74,7 +74,7 @@ function selectHeroTests() {
|
||||
it(`has selected ${targetHero.name}`, async () => {
|
||||
const page = getPageElts();
|
||||
const expectedText = `${targetHero.id} ${targetHero.name}`;
|
||||
expect((await page.selected.getText()).replace('\n', ' ')).toBe(expectedText);
|
||||
expect((await page.selected.getText()).replace(/\n/g, ' ')).toBe(expectedText);
|
||||
});
|
||||
|
||||
it('shows selected hero details', async () => {
|
||||
@@ -101,7 +101,7 @@ function updateHeroTests() {
|
||||
|
||||
it(`shows updated hero name in list`, async () => {
|
||||
const page = getPageElts();
|
||||
const hero = Hero.fromString((await page.selected.getText()).replace('\n', ' '));
|
||||
const hero = Hero.fromString((await page.selected.getText()).replace(/\n/g, ' '));
|
||||
const newName = targetHero.name + nameSuffix;
|
||||
expect(hero.id).toEqual(targetHero.id);
|
||||
expect(hero.name).toEqual(newName);
|
||||
|
||||
@@ -74,7 +74,7 @@ function selectHeroTests() {
|
||||
it(`has selected ${targetHero.name}`, async () => {
|
||||
const page = getPageElts();
|
||||
const expectedText = `${targetHero.id} ${targetHero.name}`;
|
||||
expect((await page.selected.getText()).replace('\n', ' ')).toBe(expectedText);
|
||||
expect((await page.selected.getText()).replace(/\n/g, ' ')).toBe(expectedText);
|
||||
});
|
||||
|
||||
it('shows selected hero details', async () => {
|
||||
@@ -101,7 +101,7 @@ function updateHeroTests() {
|
||||
|
||||
it(`shows updated hero name in list`, async () => {
|
||||
const page = getPageElts();
|
||||
const hero = Hero.fromString(await (await page.selected.getText()).replace('\n', ' '));
|
||||
const hero = Hero.fromString(await (await page.selected.getText()).replace(/\n/g, ' '));
|
||||
const newName = targetHero.name + nameSuffix;
|
||||
expect(hero.id).toEqual(targetHero.id);
|
||||
expect(hero.name).toEqual(newName);
|
||||
|
||||
@@ -74,7 +74,7 @@ function selectHeroTests() {
|
||||
it(`has selected ${targetHero.name}`, async () => {
|
||||
const page = getPageElts();
|
||||
const expectedText = `${targetHero.id} ${targetHero.name}`;
|
||||
expect((await page.selected.getText()).replace('\n', ' ')).toBe(expectedText);
|
||||
expect((await page.selected.getText()).replace(/\n/g, ' ')).toBe(expectedText);
|
||||
});
|
||||
|
||||
it('shows selected hero details', async () => {
|
||||
@@ -106,7 +106,7 @@ function updateHeroTests() {
|
||||
|
||||
it(`shows updated hero name in list`, async () => {
|
||||
const page = getPageElts();
|
||||
const hero = Hero.fromString((await page.selected.getText()).replace('\n', ' '));
|
||||
const hero = Hero.fromString((await page.selected.getText()).replace(/\n/g, ' '));
|
||||
const newName = targetHero.name + nameSuffix;
|
||||
expect(hero.id).toEqual(targetHero.id);
|
||||
expect(hero.name).toEqual(newName);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Index</title>
|
||||
<base href="/">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.js"></script>
|
||||
<script src="app/ajs-bootstrap/app.module.js"></script>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="center-layout-wide">
|
||||
<div class="nf-container l-flex-wrap flex-center">
|
||||
<img alt="not found" src="assets/images/support/angular-404.svg" height="300" width="300"/>
|
||||
<img alt="Not found" src="assets/images/support/angular-404.svg" height="300" width="300"/>
|
||||
<div class="nf-response l-flex-wrap center">
|
||||
<h1 class="no-anchor no-toc">Page Not Found</h1>
|
||||
<p>We're sorry. The page you are looking for cannot be found.</p>
|
||||
@@ -9,4 +9,4 @@
|
||||
<aio-file-not-found-search></aio-file-not-found-search>
|
||||
</div>
|
||||
|
||||
@reviewed 2022-02-28
|
||||
@reviewed 2023-08-20
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
# Add an animation
|
||||
|
||||
The main Angular modules for animations are `@angular/animations` and `@angular/platform-browser`.
|
||||
When you create a new project using the Angular framework, these dependencies are automatically added to your project.
|
||||
|
||||
To get started with adding Angular animations to your project, import the animation-specific modules along with standard Angular capability.
|
||||
|
||||
## Step 1: Enabling the animations module
|
||||
|
||||
Import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
|
||||
Import `provideAnimations` from `@angular/platform-browser/animations` and add it to the providers list in the `bootstrapApplication` function call.
|
||||
|
||||
```ts
|
||||
bootstrapApplication(AppComponent, {
|
||||
providers: [
|
||||
provideAnimations(),
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
For `NgModule` based applications import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
|
||||
|
||||
<code-example header="src/app/app.module.ts" path="animations/src/app/app.module.1.ts"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**NOTE**: <br />
|
||||
When you use the Angular framework to create your application, the root application module `app.module.ts` is placed in the `src/app` directory. If you are using standalone components, look at main.ts or look at your root application component.
|
||||
|
||||
</div>
|
||||
|
||||
## Step 2: Importing animation functions into component files
|
||||
|
||||
If you plan to use specific animation functions in component files, import those functions from `@angular/animations`.
|
||||
@@ -31,4 +33,4 @@ You put the trigger that defines an animation within the `animations` metadata p
|
||||
|
||||
<code-example header="src/app/app.component.ts" path="animations/src/app/app.component.ts" region="decorator"></code-example>
|
||||
|
||||
@reviewed 2022-12-19
|
||||
@reviewed 2023-08-15
|
||||
|
||||
@@ -32,13 +32,21 @@ The guide assumes that you're familiar with building basic Angular apps, as desc
|
||||
## Getting started
|
||||
|
||||
The main Angular modules for animations are `@angular/animations` and `@angular/platform-browser`.
|
||||
When you create a new project using the CLI, these dependencies are automatically added to your project.
|
||||
|
||||
To get started with adding Angular animations to your project, import the animation-specific modules along with standard Angular functionality.
|
||||
|
||||
### Step 1: Enabling the animations module
|
||||
|
||||
Import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
|
||||
Import `provideAnimations` from `@angular/platform-browser/animations` and add it to the providers list in the `bootstrapApplication` function call.
|
||||
```ts
|
||||
bootstrapApplication(AppComponent, {
|
||||
providers: [
|
||||
provideAnimations(),
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
For `NgModule` based applications import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
|
||||
|
||||
<code-example header="src/app/app.module.ts" path="animations/src/app/app.module.1.ts"></code-example>
|
||||
|
||||
@@ -337,4 +345,4 @@ Check out this [presentation](https://www.youtube.com/watch?v=rnTK9meY5us), show
|
||||
|
||||
<!-- end links -->
|
||||
|
||||
@reviewed 2022-02-28
|
||||
@reviewed 2023-08-16
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Injection context
|
||||
|
||||
The dependency injection (DI) system relies internaly on a runtime context where the current injector is available.
|
||||
The dependency injection (DI) system relies internally on a runtime context where the current injector is available.
|
||||
This means that injectors can only work when code is executed in this context.
|
||||
|
||||
The injection context is available in these situations:
|
||||
@@ -9,7 +9,7 @@ The injection context is available in these situations:
|
||||
* In the initializer for fields of such classes.
|
||||
* In the factory function specified for `useFactory` of a `Provider` or an `@Injectable`.
|
||||
* In the `factory` function specified for an `InjectionToken`.
|
||||
* Within a stack frame that is run in a injection context.
|
||||
* Within a stack frame that is run in an injection context.
|
||||
|
||||
Knowing when your are in an injection context, will allow you to use the [`inject`](api/core/inject) function to inject instances.
|
||||
|
||||
@@ -60,4 +60,4 @@ Calling [`inject`](api/core/inject) or calling `assertInInjectionContext` outsid
|
||||
|
||||
|
||||
|
||||
@reviewed 2023-04-11
|
||||
@reviewed 2023-04-11
|
||||
|
||||
@@ -124,6 +124,13 @@ v16 - v19
|
||||
| `@angular/platform-browser` | [`BrowserModule.withServerTransition`](api/platform-browser/BrowserModule#withservertransition) | v16 | v18 |
|
||||
| `@angular/platform-browser` | [`makeStateKey`, `StateKey` and `TransferState`](#platform-browser), symbols were moved to `@angular/core` | v16 | v18 |
|
||||
|
||||
|
||||
### Deprecated features that can be removed in v19 or later
|
||||
|
||||
| Area | API or Feature | Deprecated in | May be removed in |
|
||||
|:--- |:--- |:--- |:--- |
|
||||
| `@angular/core` | `PACKAGE_ROOT_URL` | v17 | v19 |
|
||||
|
||||
### Deprecated features with no planned removal version
|
||||
|
||||
| Area | API or Feature | Deprecated in | May be removed in |
|
||||
@@ -447,40 +454,6 @@ matched at all and also prevent loading the children of the `Route`. `CanMatch`
|
||||
goals as `CanLoad` but with the addition of allowing the navigation to match other routes when they reject
|
||||
(such as a wildcard route). There is no need to have both types of guards in the API surface.
|
||||
|
||||
<a id="loadChildren"></a>
|
||||
|
||||
### `loadChildren` string syntax
|
||||
|
||||
When Angular first introduced lazy routes, there wasn't browser support for dynamically loading additional JavaScript.
|
||||
Angular created its own scheme using the syntax `loadChildren: './lazy/lazy.module#LazyModule'` and built tooling to support it.
|
||||
Now that ECMAScript dynamic import is supported in many browsers, Angular is moving toward this new syntax.
|
||||
|
||||
In version 8, the string syntax for the [`loadChildren`](api/router/LoadChildren) route specification was deprecated, in favor of new syntax that uses `import()` syntax.
|
||||
|
||||
**Before**:
|
||||
|
||||
<code-example path="deprecation-guide/src/app/app.module.ts" language="typescript" region="lazyload-deprecated-syntax"></code-example>
|
||||
|
||||
**After**:
|
||||
|
||||
<code-example path="deprecation-guide/src/app/app.module.ts" language="typescript" region="lazyload-syntax"></code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Version 8 update**: When you update to version 8, the [`ng update`](cli/update) command performs the transformation automatically.
|
||||
Prior to version 7, the `import()` syntax only works in JIT mode \(with view engine\).
|
||||
|
||||
</div>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**Declaration syntax**: <br />
|
||||
It's important to follow the route declaration syntax `loadChildren: () => import('...').then(m => m.ModuleName)` to allow `ngc` to discover the lazy-loaded module and the associated `NgModule`.
|
||||
You can find the complete list of allowed syntax constructs [here](https://github.com/angular/angular-cli/blob/a491b09800b493fe01301387fa9a025f7c7d4808/packages/ngtools/webpack/src/transformers/import_factory.ts#L104-L113).
|
||||
These restrictions will be relaxed with the release of Ivy since it'll no longer use `NgFactories`.
|
||||
|
||||
</div>
|
||||
|
||||
<a id="reflect-metadata"></a>
|
||||
|
||||
### Dependency on a reflect-metadata polyfill in JIT mode
|
||||
|
||||
@@ -5,7 +5,7 @@ Angular DevTools supports Angular v12 and later when compiled with the [optimiza
|
||||
|
||||
<div class="video-container">
|
||||
|
||||
<iframe allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" allowfullscreen frameborder="0" src="https://www.youtube.com/embed/bavWOHZM6zE"></iframe>
|
||||
<iframe allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" title="DevTools Overview" allowfullscreen frameborder="0" src="https://www.youtube.com/embed/bavWOHZM6zE"></iframe>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ The `<ng-template>` element is a good choice for dynamic components because it d
|
||||
Take a closer look at the methods in `ad-banner.component.ts`.
|
||||
|
||||
`AdBannerComponent` takes an array of `AdItem` objects as input, which ultimately comes from `AdService`.
|
||||
`AdItem` objects specify the type of component to load and any data to bind to the component.`AdService` returns the actual ads making up the ad campaign.
|
||||
`AdItem` objects specify the type of component to load and any data to bind to the component. `AdService` returns the actual ads making up the ad campaign.
|
||||
|
||||
Passing an array of components to `AdBannerComponent` allows for a dynamic list of ads without static elements in the template.
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ For the sample application that this page describes, see the <live-example></liv
|
||||
A custom element extends HTML by allowing you to define a tag whose content is created and controlled by JavaScript code.
|
||||
The browser maintains a `CustomElementRegistry` of defined custom elements, which maps an instantiable JavaScript class to an HTML tag.
|
||||
|
||||
The `@angular/elements` package exports a `createCustomElement()` API that provides a bridge from Angular's component interface and change detection functionality to the built-in DOM API.
|
||||
The `@angular/elements` package exports a `createCustomElement()` API function that provides a bridge from Angular's component interface and change detection functionality to the built-in DOM API.
|
||||
|
||||
Transforming a component to a custom element makes all of the required Angular infrastructure available to the browser.
|
||||
Creating a custom element is simple and straightforward, and automatically connects your component-defined view with change detection and data binding, mapping Angular functionality to the corresponding built-in HTML equivalents.
|
||||
@@ -33,7 +33,7 @@ Once a custom element is added to the DOM for any page, it looks and behaves lik
|
||||
| | Details |
|
||||
|:--- |:--- |
|
||||
| Easy dynamic content in an Angular application | Transforming a component to a custom element provides a straightforward path to creating dynamic HTML content in your Angular application. HTML content that you add directly to the DOM in an Angular application is normally displayed without Angular processing, unless you define a *dynamic component*, adding your own code to connect the HTML tag to your application data, and participate in change detection. With a custom element, all of that wiring is taken care of automatically. |
|
||||
| Content-rich applications | If you have a content-rich application, such as the Angular app that presents this documentation, custom elements let you give your content providers sophisticated Angular functionality without requiring knowledge of Angular. For example, an Angular guide like this one is added directly to the DOM by the Angular navigation tools, but can include special elements like `<code-snippet>` that perform complex operations. All you need to tell your content provider is the syntax of your custom element. They don't need to know anything about Angular, or anything about your component's data structures or implementation. |
|
||||
| Content-rich applications | If you have a content-rich application, such as the Angular application described in this guide, custom elements let you give your content providers sophisticated Angular functionality without requiring knowledge of Angular. For example, an Angular guide like this one is added directly to the DOM by the Angular navigation tools, but can include special elements like `<code-snippet>` that perform complex operations. All you need to tell your content provider is the syntax of your custom element. They don't need to know anything about Angular, or anything about your component's data structures or implementation. |
|
||||
|
||||
### How it works
|
||||
|
||||
@@ -92,8 +92,8 @@ Component properties and logic maps directly into HTML attributes and the browse
|
||||
For example, for a component with `@Input('myInputProp') inputProp`, the corresponding custom element defines an attribute `my-input-prop`.
|
||||
|
||||
* Component outputs are dispatched as HTML [Custom Events](https://developer.mozilla.org/docs/Web/API/CustomEvent), with the name of the custom event matching the output name.
|
||||
For example, for a component with `@Output() valueChanged = new EventEmitter()`, the corresponding custom element dispatches events with the name "valueChanged", and the emitted data is stored on the event's `detail` property.
|
||||
If you provide an alias, that value is used; for example, `@Output('myClick') clicks = new EventEmitter<string>();` results in dispatch events with the name "myClick".
|
||||
For example, for a component with `@Output() valueChanged = new EventEmitter()`, the corresponding custom element dispatches events with the name `valueChanged`, and the emitted data is stored on the event's `detail` property.
|
||||
If you provide an alias, that value will be used instead; for example, `@Output('myClick') clicks = new EventEmitter<string>();` results in dispatch events with the name `myClick`.
|
||||
|
||||
For more information, see Web Component documentation for [Creating custom events](https://developer.mozilla.org/docs/Web/Guide/Events/Creating_and_triggering_events#Creating_custom_events).
|
||||
|
||||
@@ -124,14 +124,17 @@ npm install @angular/elements --save
|
||||
Previously, when you wanted to add a component to an application at runtime, you had to define a *dynamic component*, and then you would have to load it, attach it to an element in the DOM, and wire up all of the dependencies, change detection, and event handling, as described in [Dynamic Component Loader](guide/dynamic-component-loader).
|
||||
|
||||
Using an Angular custom element makes the process much simpler and more transparent, by providing all of the infrastructure and framework automatically —all you have to do is define the kind of event handling you want.
|
||||
\(You do still have to exclude the component from compilation, if you are not going to use it in your application.\)
|
||||
|
||||
<div class="alert is-helpful">
|
||||
You do still have to exclude the component from compilation, if you are not going to use it in your application.
|
||||
</div>
|
||||
|
||||
The following Popup Service example application defines a component that you can either load dynamically or convert to a custom element.
|
||||
|
||||
| Files | Details |
|
||||
|:--- |:--- |
|
||||
| `popup.component.ts` | Defines a simple pop-up element that displays an input message, with some animation and styling. |
|
||||
| `popup.service.ts` | Creates an injectable service that provides two different ways to invoke the `PopupComponent`; as a dynamic component, or as a custom element Notice how much more setup is required for the dynamic-loading method. |
|
||||
| `popup.service.ts` | Creates an injectable service that provides two different ways to invoke the `PopupComponent`; as a dynamic component, or as a custom element. Notice how much more setup is required for the dynamic-loading method. |
|
||||
| `app.module.ts` | Adds the `PopupComponent` in the module's `declarations` list. |
|
||||
| `app.component.ts` | Defines the application's root component, which uses the `PopupService` to add the pop-up to the DOM at run time. When the application runs, the root component's constructor converts `PopupComponent` to a custom element. |
|
||||
|
||||
@@ -159,7 +162,7 @@ Additionally, these custom elements will have a property for each input of the c
|
||||
For example, our `popup-element` has a `message` property of type `string`.
|
||||
|
||||
There are a few options if you want to get correct types for your custom elements.
|
||||
Assume you create a `my-dialog` custom element based on the following component:
|
||||
Assuming you create a `my-dialog` custom element based on the following component:
|
||||
|
||||
<code-example format="typescript" language="typescript">
|
||||
|
||||
@@ -216,4 +219,4 @@ document.querySelector('my-other-element') //--> NgElement & WithPropert
|
||||
|
||||
<!-- end links -->
|
||||
|
||||
@reviewed 2022-02-28
|
||||
@reviewed 2023-04-27
|
||||
|
||||
@@ -97,7 +97,7 @@ Angular components, templates, and styles go here.
|
||||
| `app/app.component.html` | Defines the HTML template associated with the root `AppComponent`. |
|
||||
| `app/app.component.css` | Defines the base CSS stylesheet for the root `AppComponent`. |
|
||||
| `app/app.component.spec.ts` | Defines a unit test for the root `AppComponent`. |
|
||||
| `app/app.module.ts` | Defines the root module, named `AppModule`, that tells Angular how to assemble the application. Initially declares only the `AppComponent`. As you add more components to the app, they must be declared here.<br><br>_Only generated when using the `--standalone` option._ |
|
||||
| `app/app.module.ts` | Defines the root module, named `AppModule`, that tells Angular how to assemble the application. Initially declares only the `AppComponent`. As you add more components to the app, they must be declared here.<br><br>_This file is not generated when using the `--standalone` option._ |
|
||||
|
||||
### Application configuration files
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ For example, in the following `SelfComponent`, notice the injected `LeafService`
|
||||
|
||||
<code-example header="src/app/self-no-data/self-no-data.component.ts" path="resolution-modifiers/src/app/self-no-data/self-no-data.component.ts" region="self-no-data-component"></code-example>
|
||||
|
||||
In this example, there is a parent provider and injecting the service will return the value, however, injecting the service with `@Self()` and `@Optional()` will return `null` because `@Self()` tells the injector to stop searching in the current host element.
|
||||
In this example, there is a parent provider and injecting the service will return the value, however, injecting the service with `@Self()` and `@Optional()` will return `null` because `@Self()` tells the injector to only search in the current host element.
|
||||
|
||||
Another example shows the component class with a provider for `FlowerService`.
|
||||
In this case, the injector looks no further than the current `ElementInjector` because it finds the `FlowerService` and returns the tulip <code>🌷</code>.
|
||||
|
||||
@@ -125,6 +125,13 @@ If you choose to set this setting in your tsconfig, we recommend to set it only
|
||||
|
||||
</div>
|
||||
|
||||
<a id="cdn-configuration"></a>
|
||||
### CDN Optimizations
|
||||
|
||||
Many CDNs offer a feature that will try to optimize your rendered application by stripping all nodes from the rendered DOM that it thinks are unnecessary, which includes comment nodes. Comment nodes are an essential part of Angular's functioning and are critical for hydration to work. You will need to disable this CDN feature in order to ensure your application loads and hydrates.
|
||||
|
||||
If CDN optimization is enabled and you have hydration enabled, when you attempt to load the page you will encounter error [NG0507](https://angular.io/errors/NG0507). If you see this error, you should go and disable the CDN optimization.
|
||||
|
||||
### Custom or Noop Zone.js are not yet supported
|
||||
|
||||
Hydration relies on a signal from Zone.js when it becomes stable inside an application, so that Angular can start the serialization process on the server or post-hydration cleanup on the client to remove DOM nodes that remained unclaimed.
|
||||
@@ -184,4 +191,4 @@ re-rendering those components from scratch.
|
||||
|
||||
There are a number of third party libraries that depend on DOM manipulation to be able to render. D3 charts is a prime example. These libraries worked without hydration, but they may cause DOM mismatch errors when hydration is enabled. For now, if you encounter DOM mismatch errors using one of these libraries, you can add the `ngSkipHydration` attribute to the component that renders using that library.
|
||||
|
||||
@reviewed 2023-06-21
|
||||
@reviewed 2023-08-14
|
||||
|
||||
@@ -20,7 +20,7 @@ For a quick introduction to localization and internationalization watch this vid
|
||||
|
||||
<div class="video-container">
|
||||
|
||||
<iframe allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" allowfullscreen frameborder="0" src="https://www.youtube.com/embed/KNTN-nsbV7M"></iframe>
|
||||
<iframe allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" title="Angular Internationalization" allowfullscreen frameborder="0" src="https://www.youtube.com/embed/KNTN-nsbV7M"></iframe>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -220,7 +220,7 @@ You may want to have images displayed at varying widths on differently-sized scr
|
||||
|
||||
The `sizes` attribute in the above example says "I expect this image to be 100 percent of the screen width on devices under 768px wide. Otherwise, I expect it to be 50 percent of the screen width.
|
||||
|
||||
For additional information about the `sizes` attribute, see [web.dev](https://web.dev/learn/design/responsive-images/#sizes) or [mdn](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes).
|
||||
For additional information about the `sizes` attribute, see [web.dev](https://web.dev/learn/design/responsive-images/#sizes) or [MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes).
|
||||
|
||||
## Configuring an image loader for `NgOptimizedImage`
|
||||
|
||||
|
||||
@@ -75,13 +75,6 @@ ng new customer-app --routing
|
||||
This creates an application called `customer-app` and the `--routing` flag generates a file called `app-routing.module.ts`. This is one of the files you need for setting up lazy loading for your feature module.
|
||||
Navigate into the project by issuing the command `cd customer-app`.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The `--routing` option requires Angular CLI version 8.1 or higher.
|
||||
See [Keeping Up to Date](guide/updating).
|
||||
|
||||
</div>
|
||||
|
||||
### Create a feature module with routing
|
||||
|
||||
Next, you need a feature module with a component to route to.
|
||||
@@ -105,17 +98,6 @@ Instead, it adds the declared route, `customers` to the `routes` array declared
|
||||
Notice that the lazy-loading syntax uses `loadChildren` followed by a function that uses the browser's built-in `import('...')` syntax for dynamic imports.
|
||||
The import path is the relative path to the module.
|
||||
|
||||
<div class="callout is-helpful">
|
||||
|
||||
<header>String-based lazy loading</header>
|
||||
|
||||
In Angular version 8, the string syntax for the `loadChildren` route specification [was deprecated](guide/deprecations#loadchildren-string-syntax) in favor of the `import()` syntax.
|
||||
You can opt into using string-based lazy loading \(`loadChildren: './path/to/module#Module'`\) by including the lazy-loaded routes in your `tsconfig` file, which includes the lazy-loaded files in the compilation.
|
||||
|
||||
By default the Angular CLI generates projects with stricter file inclusions intended to be used with the `import()` syntax.
|
||||
|
||||
</div>
|
||||
|
||||
### Add another feature module
|
||||
|
||||
Use the same command to create a second lazy-loaded feature module with routing, along with its stub component.
|
||||
@@ -251,7 +233,7 @@ For more information, see the [`forRoot()` pattern](guide/singleton-services#for
|
||||
## Preloading
|
||||
|
||||
Preloading improves UX by loading parts of your application in the background.
|
||||
You can preload modules, standalone components or component data.
|
||||
You can preload modules, standalone components or component data.
|
||||
|
||||
### Preloading modules and standalone components
|
||||
|
||||
|
||||
@@ -138,6 +138,97 @@ data$ = http.get('...').pipe(takeUntilDestroyed());
|
||||
|
||||
By default, `takeUntilDestroyed` must be called in an [injection context](/guide/dependency-injection-context) so that it can access `DestroyRef`. If an injection context isn't available, you can explicitly provide a `DestroyRef`.
|
||||
|
||||
## Reading and writing the DOM
|
||||
|
||||
Sometimes it's necessary to use browser-only APIs to manually read or write the DOM. This can be challenging to do with the [lifecycle events](#lifecycle-event-sequence) above, as they will also run during [server-side rendering and pre-rendering](guide/glossary#server-side-rendering). For this purpose, Angular provides `afterRender` and `afterNextRender`. These functions can be used unconditionally, but will only have an effect on the browser. Both functions accept a callback that will run after the next [change detection](/guide/glossary#change-detection) cycle (including any nested cycles) has completed.
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
`afterRender` and `afterNextRender` are available for [developer preview](/guide/releases#developer-preview). They are ready for you to try, but they might change before they are stable.
|
||||
|
||||
</div>
|
||||
|
||||
| Function | Purpose | Timing |
|
||||
| ------ | ------- | ------ |
|
||||
| `afterNextRender` | Perform one-time initialization, or observe a single, specific change to the DOM. <br /> <div class="alert is-helpful">As a rule of thumb, you should use `afterRender` instead if you need to manually read or write any layout data such as size or location.</div> See details in [One-time initialization](#one-time-initialization) in this document. | _Once_ after the next change detection cycle. |
|
||||
| `afterRender` | Synchronize state with the DOM. See details in [Handling synchronization](#handling-synchronization) in this document. | After _every_ change detection cycle that follows. |
|
||||
|
||||
### One-time initialization
|
||||
|
||||
Generally, you will want to use `afterNextRender` to perform any one-time initialization, such as for a third-party library, or for browser-only APIs.
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'my-chart-cmp',
|
||||
template: `<div #chart>{{ ... }}</div>`,
|
||||
})
|
||||
export class MyChartCmp {
|
||||
@ViewChild('chart') chartRef: ElementRef;
|
||||
chart: MyChart|null;
|
||||
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.chart = new MyChart(this.chartRef.nativeElement);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Instead of attempting to recreate their behaviors with `afterRender`, you should prefer to use built-in browser APIs like `ResizeObserver` and `IntersectionObserver` wherever possible. You can use `afterNextRender` to safely initialize such APIs on the browser only.
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'my-cmp',
|
||||
template: `<span #content>{{ ... }}</span>`,
|
||||
})
|
||||
export class MyComponent {
|
||||
resizeObserver: ResizeObserver|null = null;
|
||||
@ViewChild('content') contentRef: ElementRef;
|
||||
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.resizeObserver = new ResizeObserver(() => {
|
||||
console.log('Content was resized');
|
||||
});
|
||||
|
||||
this.resizeObserver.observe(this.contentRef.nativeElement);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.resizeObserver?.disconnect();
|
||||
this.resizeObserver = null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
As a rule of thumb, `afterNextRender` should be used to observe _discrete_ changes to the DOM, such as element creation or deletion. For manually reading or writing data that tends to change frequently, such as size or location, you should generally prefer to use `afterRender` instead.
|
||||
|
||||
</div>
|
||||
|
||||
### Handling synchronization
|
||||
|
||||
As an escape hatch for when the browser does not provide a better API to do so, you can use `afterRender` to perform any additional read or writes to the DOM every time Angular finishes mutating it.
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'my-cmp',
|
||||
template: `<span #content>{{ ... }}</span>`,
|
||||
})
|
||||
export class MyComponent {
|
||||
@ViewChild('content') contentRef: ElementRef;
|
||||
|
||||
constructor() {
|
||||
afterRender(() => {
|
||||
const elem = this.contentRef.nativeElement;
|
||||
console.log(`content position: (${elem.offsetLeft}, ${elem.offsetTop})`);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## General examples
|
||||
|
||||
The following examples demonstrate the call sequence and relative frequency of the various lifecycle events, and how the hooks can be used separately or together for components and directives.
|
||||
|
||||
@@ -183,6 +183,12 @@ This may be because we want to gather feedback from real applications before sta
|
||||
|
||||
The policies and practices that are described in this document do not apply to APIs marked as Developer Preview. Such APIs can change at any time, even in new patch versions of the framework. Teams should decide for themselves whether the benefits of using Developer Preview APIs are worth the risk of breaking changes outside of our normal use of semantic versioning.
|
||||
|
||||
## Experimental
|
||||
|
||||
These are APIs might not become stable at all or have significant changes before becoming stable.
|
||||
|
||||
The policies and practices that are described in this document do not apply to APIs marked as experimental. Such APIs can change at any time, even in new patch versions of the framework. Teams should decide for themselves whether the benefits of using experimental APIs are worth the risk of breaking changes outside of our normal use of semantic versioning.
|
||||
|
||||
<!-- links -->
|
||||
|
||||
<!-- external links -->
|
||||
|
||||
@@ -21,7 +21,7 @@ Start with the top-level component that hosts the view, and nest animations in t
|
||||
|
||||
To enable routing transition animation, do the following:
|
||||
|
||||
1. Import the routing module into the application and create a routing configuration that defines the possible routes.
|
||||
1. Create a routing configuration that defines the possible routes. For NgModule based applications, this will include creating a `RouterModule` and adding it to the main `AppModule`.
|
||||
1. Add a router outlet to tell the Angular router where to place the activated components in the DOM.
|
||||
1. Define the animation.
|
||||
|
||||
@@ -37,15 +37,27 @@ Implement a router transition animation that slides in the new view to the right
|
||||
|
||||
## Route configuration
|
||||
|
||||
To begin, configure a set of routes using methods available in the `RouterModule` class.
|
||||
This route configuration tells the router how to navigate.
|
||||
To begin, configure a set of routes. This route configuration tells the router how to navigate.
|
||||
|
||||
Use the `RouterModule.forRoot` method to define a set of routes.
|
||||
Also, add `RouterModule` to the `imports` array of the main module, `AppModule`.
|
||||
- Create an array called `routes` in `app.routes.ts` to define a set of routes.
|
||||
- Add the routes to the `provideRouter` function in the providers array in `app.config.ts`.
|
||||
|
||||
```ts
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideRouter(routes)
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
**NOTE**: <br />
|
||||
For `NgModule` based applications:
|
||||
|
||||
Use the `RouterModule.forRoot` method to define a set of routes.
|
||||
Also, add `RouterModule` to the `imports` array of the main module, `AppModule`.
|
||||
|
||||
Use the `RouterModule.forRoot` method in the root module, `AppModule`, to register top-level application routes and providers.
|
||||
For feature modules, call the `RouterModule.forChild` method instead.
|
||||
|
||||
@@ -53,7 +65,7 @@ For feature modules, call the `RouterModule.forChild` method instead.
|
||||
|
||||
The following configuration defines the possible routes for the application.
|
||||
|
||||
<code-example header="src/app/app.module.ts" path="animations/src/app/app.module.ts" region="route-animation-data"></code-example>
|
||||
<code-example header="src/app/app.routes.ts" path="animations/src/app/app.routes.ts" region="route-animation-data"></code-example>
|
||||
|
||||
The `home` and `about` paths are associated with the `HomeComponent` and `AboutComponent` views.
|
||||
The route configuration tells the Angular router to instantiate the `HomeComponent` and `AboutComponent` views when the navigation matches the corresponding path.
|
||||
|
||||
@@ -1623,6 +1623,29 @@ This time, the value of `'popup'` is `null`.
|
||||
That's not a route, but it is a legitimate value.
|
||||
Setting the popup `RouterOutlet` to `null` clears the outlet and removes the secondary popup route from the current URL.
|
||||
|
||||
<div class="alert is-critical">
|
||||
|
||||
**Note:** All commands in the array passed to `Router.navigate()` target a _specific segment_ in the `UrlTree`.
|
||||
We specify the parent of the `ActivatedRoute` as the `relativeTo` option because we want to remove `'popup'` from the segment which holds its reference.
|
||||
It's important to always be aware of which segments the commands will be applied to.
|
||||
|
||||
</div>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
When `relativeTo` is not provided to the `Router.navigate()` method, the commands are processed starting at the root.
|
||||
We could omit the `relativeTo` option in this particular example because the `'popup'` outlet appears at the root level of the configuration.
|
||||
|
||||
</div>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
If you want to close an outlet which appears at any segment depth, you could accomplish
|
||||
this by creating a `UrlTree` from the current URL, recursively clearing segment `children` matching the outlet name, and finally
|
||||
calling `Router.navigateByUrl()` with the `root` segment of the current `UrlTree`.
|
||||
|
||||
</div>
|
||||
|
||||
<a id="guards"></a>
|
||||
<a id="milestone-5-route-guards"></a>
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ In addition, using the `onActionClick` property on the `data` object, you can ti
|
||||
{"action": "foo", "title": "Open new tab"},
|
||||
{"action": "bar", "title": "Focus last"},
|
||||
{"action": "baz", "title": "Navigate last"},
|
||||
{"action": "qux", "title": "Send request in the background"}
|
||||
{"action": "qux", "title": "Send request in the background"},
|
||||
{"action": "other", "title": "Just notify existing clients"}
|
||||
],
|
||||
"data": {
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
|
||||
## Creating standalone components
|
||||
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/x5PZwb4XurU" title="YouTube video player" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
<div class="video-container">
|
||||
|
||||
<iframe src="https://www.youtube.com/embed/x5PZwb4XurU" title="Getting started with standalone components" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
|
||||
</div>
|
||||
|
||||
### The `standalone` flag and component `imports`
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ Congratulations, your application has been converted to standalone 🎉. These a
|
||||
* Find and remove any remaining `NgModule` declarations: since the ["Remove unnecessary NgModules" step](#remove-unnecessary-ngmodules) cannot remove all modules automatically, you may have to remove the remaining declarations manually.
|
||||
* Run the project's unit tests and fix any failures.
|
||||
* Run any code formatters, if the project uses automatic formatting.
|
||||
* Run any linters in your project and fix new warnings. Some linters support a `--fix` flag that may resolve so warnings automatically.
|
||||
* Run any linters in your project and fix new warnings. Some linters support a `--fix` flag that may resolve some of your warnings automatically.
|
||||
|
||||
## Migration modes
|
||||
The migration has the following modes:
|
||||
|
||||
@@ -309,7 +309,7 @@ The test must become *asynchronous*.
|
||||
#### Async test with `fakeAsync()`
|
||||
|
||||
To use `fakeAsync()` functionality, you must import `zone.js/testing` in your test setup file.
|
||||
If you created your project with the Angular CLI, `zone-testing` is already imported in `src/test.ts`.
|
||||
If you created your project with the Angular CLI, `zone-testing` has already been added for you.
|
||||
|
||||
The following test confirms the expected behavior when the service returns an `ErrorObservable`.
|
||||
|
||||
@@ -483,7 +483,7 @@ Then you can assert that the quote element displays the expected text.
|
||||
#### Async test with `waitForAsync()`
|
||||
|
||||
To use `waitForAsync()` functionality, you must import `zone.js/testing` in your test setup file.
|
||||
If you created your project with the Angular CLI, `zone-testing` is already imported in `src/test.ts`.
|
||||
If you created your project with the Angular CLI, `zone-testing` has already been added for you.
|
||||
|
||||
Here's the previous `fakeAsync()` test, re-written with the `waitForAsync()` utility.
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ To test your Angular CLI application in Continuous integration \(CI\) run the fo
|
||||
|
||||
<code-example format="shell" language="shell">
|
||||
|
||||
ng test --no-watch --no-progress
|
||||
ng test --no-watch --no-progress --browsers=ChromeHeadless
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
@@ -12,7 +12,11 @@ As background for this guide, you should already be familiar with [Angular React
|
||||
|
||||
## Overview of Typed Forms
|
||||
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/L-odCf4MfJc" title="YouTube video player" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
<div class="video-container">
|
||||
|
||||
<iframe src="https://www.youtube.com/embed/L-odCf4MfJc" title="Angular Typed Forms" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
|
||||
</div>
|
||||
|
||||
With Angular reactive forms, you explicitly specify a *form model*. As a simple example, consider this basic user login form:
|
||||
|
||||
|
||||
@@ -235,6 +235,13 @@ The render function renders the view within the `<app>` tag of the template, cre
|
||||
|
||||
Finally, the server returns the rendered page to the client.
|
||||
|
||||
### Caching data when using HttpClient
|
||||
By default, the [`provideClientHydration()`](api/platform-browser/provideClientHydration) function enables the recommended set of features for the optimal performance for most of the applications. It includes the following features:
|
||||
* Reconciling DOM hydration (learn more about it [here](guide/hydration)).
|
||||
* [`HttpClient`](api/common/http/HttpClient) response caching while running on the server and transferring this cache to the client to avoid extra HTTP requests.
|
||||
|
||||
While running on the server, data caching is performed for every `HEAD` and `GET` requests done by the [`HttpClient`](api/common/http/HttpClient). After that this information is serialized and transferred to a browser as a part of the initial HTML sent from the server after server-side rendering. In a browser, [`HttpClient`](api/common/http/HttpClient) checks whether it has data in the cache and if so, reuses it instead of making a new HTTP request during initial application rendering. HttpClient stops using the cache once an application becomes [stable](api/core/ApplicationRef#isStable) while running in a browser.
|
||||
|
||||
### Working around the browser APIs
|
||||
|
||||
Because a Universal application doesn't execute in the browser, some of the browser APIs and capabilities might be missing on the server.
|
||||
|
||||
@@ -10,7 +10,7 @@ covers [Angular versions under active support](guide/releases#actively-supported
|
||||
|
||||
| Angular | Node.js | TypeScript | RxJS |
|
||||
|--------------------|--------------------------------------|----------------|--------------------|
|
||||
| 16.1.x | ^16.14.0 \|\| ^18.10.0 | >=4.9.3 <5.2.0 | ^6.5.3 \|\| ^7.4.0 |
|
||||
| 16.1.x \|\| 16.2.x | ^16.14.0 \|\| ^18.10.0 | >=4.9.3 <5.2.0 | ^6.5.3 \|\| ^7.4.0 |
|
||||
| 16.0.x | ^16.14.0 \|\| ^18.10.0 | >=4.9.3 <5.1.0 | ^6.5.3 \|\| ^7.4.0 |
|
||||
| 15.1.x \|\| 15.2.x | ^14.20.0 \|\| ^16.13.0 \|\| ^18.10.0 | >=4.8.2 <5.0.0 | ^6.5.3 \|\| ^7.4.0 |
|
||||
| 15.0.x | ^14.20.0 \|\| ^16.13.0 \|\| ^18.10.0 | ~4.8.2 | ^6.5.3 \|\| ^7.4.0 |
|
||||
|
||||
@@ -86,7 +86,7 @@ To clarify how changes are detected and values updated, consider the following c
|
||||
value = v;
|
||||
// call detectChange manually
|
||||
detectChange();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// Example 5: some other asynchronous APIs
|
||||
document.getElementById('canvas').toBlob(blob => {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
@@ -74,7 +74,6 @@
|
||||
"name": "Alyssa Nicoll",
|
||||
"picture": "alyssa.jpg",
|
||||
"twitter": "alyssanicoll",
|
||||
"website": "http://alyssa.io",
|
||||
"bio": "Alyssa is an Angular Developer Advocate for KUI and a GDE. Her two degrees (Web Design & Development and Psychology) feed her speaking career. She has spoken at over 35 conferences internationally. She is a weekly panelist on Adventures in Angular and Angular Air, which have a combined following of over 16,000 listeners. She enjoys gaming, scuba diving, and has a newborn that fondly goes by 'Mr. Milks'.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
@@ -188,7 +187,6 @@
|
||||
"name": "Brooke Avery",
|
||||
"picture": "bravery_pic.png",
|
||||
"twitter": "JediBravery",
|
||||
"website": "https://devlife.show",
|
||||
"bio": "Brooke is a software engineer, GDE, & community builder. She is the director of the Angular Community Meetup, a co-producer/host of the Dev.Life Podcast, & has been a co-organizer for ng-conf. Brooke has a strong passion for education & helping others find success in their developer journeys. Outside of programming, Brooke loves to geek out on Star Wars and the Disney Parks.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
@@ -256,6 +254,14 @@
|
||||
"lead": "dgp1130",
|
||||
"picture": "clydin.jpg"
|
||||
},
|
||||
"connieleung": {
|
||||
"name": "Connie Leung",
|
||||
"picture": "connieleung.jpg",
|
||||
"twitter": "connieleung404",
|
||||
"website": "https://www.blueskyconnie.com",
|
||||
"bio": "Connie is a software architect who is passionate about Angular, NestJS and web technologies. She loves coding with Angular and NestJS, and blogging about these topics to share knowledge to members in the communities. Connie is the channel host of Angular Nation East where she hosts events and do talks to Angular developers in the APAC region.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
"coryrylan": {
|
||||
"name": "Cory Rylan",
|
||||
"picture": "cory-rylan.jpg",
|
||||
@@ -502,7 +508,7 @@
|
||||
"name": "Jordan Powell",
|
||||
"picture": "jordanpowell.jpg",
|
||||
"twitter": "jordanpowell88",
|
||||
"website": "https://jordanpowell88.com",
|
||||
"website": "https://jordanpowell.online",
|
||||
"bio": "Jordan is a GDE (Google Developer Expert) and a self taught software engineer who is passionate about writing 'good code' that is easy to read, test and maintain over time. He has over a decade of freelance experience in software development, marketing, design and video production. He currently is a Developer Experience Engineer at Cypress.io and also serves as the CEO & Co-Founder for the non-profit Dream On: Global.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
@@ -587,7 +593,6 @@
|
||||
"name": "Kim Maida",
|
||||
"picture": "kimmaida.jpg",
|
||||
"twitter": "KimMaida",
|
||||
"website": "https://kmaida.io/",
|
||||
"bio": "Kim is an an Angular consultant, developer, speaker, writer, and Google Developer Expert. She is passionate about learning from and sharing knowledge with other developers through blogging, speaking, workshops, and open source.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
@@ -792,7 +797,6 @@
|
||||
"pascalprecht": {
|
||||
"name": "Pascal Precht",
|
||||
"picture": "pascalprecht.jpg",
|
||||
"website": "https://twitter.com/PascalPrecht",
|
||||
"bio": "Pascal is a software engineer, author and Google Developer Expert for the Angular team. He loves contributing to open source and is the creator of the popular angular-translate module. In his spare time he’s fiddling with EDM production.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
@@ -839,7 +843,6 @@
|
||||
"name": "Ricardo Chavarria",
|
||||
"picture": "ricardo-chavarria.jpg",
|
||||
"twitter": "ricardo_chl",
|
||||
"website": "https://ricardochavarria.dev",
|
||||
"bio": "Ricardo Chavarria is a software developer with focus in frontend technologies. Organizer of Angular Honduras Community and Ng Conf Honduras. Also is Google Developer Expert in Angular and Auth0 ambassador.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
@@ -1084,7 +1087,7 @@
|
||||
"name": "Jay Bell",
|
||||
"picture": "jaybell.jpg",
|
||||
"twitter": "jaycooperbell",
|
||||
"website": "tech.trellis.org",
|
||||
"website": "https://tech.trellis.org",
|
||||
"bio": "Jay is the CTO and Co-Founder of a Social Enterprise in Canada that is using Angular and technology to empower global collective impact in the non-profit and charity industries. He is an avid contributor to Nx and loves Angular, NgRx and Nest. Jay loves to share knowledge he has learned from figuring out problems (complex or otherwise) so that others can solve them easier the next time.",
|
||||
"groups": ["GDE"]
|
||||
},
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
</h1>
|
||||
|
||||
<div class="cta-button-container">
|
||||
<p class="cta-link">
|
||||
<div class="cta-link">
|
||||
<a class="button hero-cta no-print" href="quick-start">Try Angular</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -112,12 +112,6 @@
|
||||
"logo": "",
|
||||
"title": "NgRuAir",
|
||||
"url": "https://github.com/ngRuAir/ngruair"
|
||||
},
|
||||
"ngxp": {
|
||||
"desc": "Weekly technical-adjacent podcast by Brooke Avery & Erik Slack. Don't just code in Angular, come enjoy the Angular Experience!",
|
||||
"logo": "",
|
||||
"title": "Angular Experience (NgXP)",
|
||||
"url": "https://ngxp.show"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -574,6 +568,11 @@
|
||||
"desc": "NGX Cookie Service is an Angular Library that can be used to read, set and delete browser cookies",
|
||||
"title": "NGX Cookie Service",
|
||||
"url": "https://github.com/stevermeister/ngx-cookie-service"
|
||||
},
|
||||
"flowbite": {
|
||||
"desc": "Open-source UI component library built with the utility-classes from Tailwind CSS and with official support for Angular.",
|
||||
"title": "Flowbite",
|
||||
"url": "https://flowbite.com/docs/getting-started/angular/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1525,7 +1525,7 @@
|
||||
{
|
||||
"url": "https://github.com/angular/angular/issues",
|
||||
"title": "Report Issues",
|
||||
"tooltip": "Post issues and suggestions on github."
|
||||
"tooltip": "Post issues and suggestions on GitHub."
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/angular/code-of-conduct/blob/main/CODE_OF_CONDUCT.md",
|
||||
|
||||
@@ -60,11 +60,11 @@ The Angular Router displays components based on the browser's URL and [your defi
|
||||
|
||||
In this section, you'll use the Angular Router to combine the `products` data and route information to display the specific details for each product.
|
||||
|
||||
1. In `product-details.component.ts`, import `ActivatedRoute` from `@angular/router`, and the `products` array from `../products`.
|
||||
1. In `product-details.component.ts`, import `ActivatedRoute` from `@angular/router`, import `OnInit` from `@angular/core`, and the `products` array from `../products`.
|
||||
|
||||
<code-example header="src/app/product-details/product-details.component.ts" path="getting-started/src/app/product-details/product-details.component.1.ts" region="imports"></code-example>
|
||||
|
||||
1. Define the `product` property.
|
||||
1. Define the `product` property. The `implements OnInit` statement indicates that the class implements the `OnInit` interface, requiring the implementation of the `ngOnInit` method for initialization tasks when the component is created.
|
||||
|
||||
<code-example header="src/app/product-details/product-details.component.ts" path="getting-started/src/app/product-details/product-details.component.1.ts" region="product-prop"></code-example>
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ There are a few more lessons to complete before that happens.
|
||||
|
||||
In this lesson, you created an interface that created a new data type for your app.
|
||||
This new data type makes it possible for you to specify where `HousingLocation` data is required.
|
||||
This new data type also makes it possible for your IDE and the TypeScript compiler can ensure that `HousingLocation` data is used where it's required.
|
||||
This new data type also makes your IDE and the TypeScript compiler ensure that `HousingLocation` data is used where it's required.
|
||||
|
||||
If you are having any trouble with this lesson, you can review the completed code for it in the <live-example></live-example>.
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ JSON Server is an open source tool used to create mock REST APIs. You'll use it
|
||||
"name": "Acme Fresh Start Housing",
|
||||
"city": "Chicago",
|
||||
"state": "IL",
|
||||
"photo": "/assets/bernard-hermant-CLKGGwIBTaY-unsplash.jpg",
|
||||
"photo": "https://angular.io/assets/images/tutorials/faa/bernard-hermant-CLKGGwIBTaY-unsplash.jpg",
|
||||
"availableUnits": 4,
|
||||
"wifi": true,
|
||||
"laundry": true
|
||||
@@ -43,7 +43,7 @@ JSON Server is an open source tool used to create mock REST APIs. You'll use it
|
||||
"name": "A113 Transitional Housing",
|
||||
"city": "Santa Monica",
|
||||
"state": "CA",
|
||||
"photo": "/assets/brandon-griggs-wR11KBaB86U-unsplash.jpg",
|
||||
"photo": "https://angular.io/assets/images/tutorials/faa/brandon-griggs-wR11KBaB86U-unsplash.jpg",
|
||||
"availableUnits": 0,
|
||||
"wifi": false,
|
||||
"laundry": true
|
||||
@@ -53,7 +53,7 @@ JSON Server is an open source tool used to create mock REST APIs. You'll use it
|
||||
"name": "Warm Beds Housing Support",
|
||||
"city": "Juneau",
|
||||
"state": "AK",
|
||||
"photo": "/assets/i-do-nothing-but-love-lAyXdl1-Wmc-unsplash.jpg",
|
||||
"photo": "https://angular.io/assets/images/tutorials/faa/i-do-nothing-but-love-lAyXdl1-Wmc-unsplash.jpg",
|
||||
"availableUnits": 1,
|
||||
"wifi": false,
|
||||
"laundry": false
|
||||
@@ -63,7 +63,7 @@ JSON Server is an open source tool used to create mock REST APIs. You'll use it
|
||||
"name": "Homesteady Housing",
|
||||
"city": "Chicago",
|
||||
"state": "IL",
|
||||
"photo": "/assets/ian-macdonald-W8z6aiwfi1E-unsplash.jpg",
|
||||
"photo": "https://angular.io/assets/images/tutorials/faa/ian-macdonald-W8z6aiwfi1E-unsplash.jpg",
|
||||
"availableUnits": 1,
|
||||
"wifi": true,
|
||||
"laundry": false
|
||||
@@ -73,7 +73,7 @@ JSON Server is an open source tool used to create mock REST APIs. You'll use it
|
||||
"name": "Happy Homes Group",
|
||||
"city": "Gary",
|
||||
"state": "IN",
|
||||
"photo": "/assets/krzysztof-hepner-978RAXoXnH4-unsplash.jpg",
|
||||
"photo": "https://angular.io/assets/images/tutorials/faa/krzysztof-hepner-978RAXoXnH4-unsplash.jpg",
|
||||
"availableUnits": 1,
|
||||
"wifi": true,
|
||||
"laundry": false
|
||||
@@ -83,7 +83,7 @@ JSON Server is an open source tool used to create mock REST APIs. You'll use it
|
||||
"name": "Hopeful Apartment Group",
|
||||
"city": "Oakland",
|
||||
"state": "CA",
|
||||
"photo": "/assets/r-architecture-JvQ0Q5IkeMM-unsplash.jpg",
|
||||
"photo": "https://angular.io/assets/images/tutorials/faa/r-architecture-JvQ0Q5IkeMM-unsplash.jpg",
|
||||
"availableUnits": 2,
|
||||
"wifi": true,
|
||||
"laundry": true
|
||||
@@ -93,7 +93,7 @@ JSON Server is an open source tool used to create mock REST APIs. You'll use it
|
||||
"name": "Seriously Safe Towns",
|
||||
"city": "Oakland",
|
||||
"state": "CA",
|
||||
"photo": "/assets/phil-hearing-IYfp2Ixe9nM-unsplash.jpg",
|
||||
"photo": "https://angular.io/assets/images/tutorials/faa/phil-hearing-IYfp2Ixe9nM-unsplash.jpg",
|
||||
"availableUnits": 5,
|
||||
"wifi": true,
|
||||
"laundry": true
|
||||
@@ -103,7 +103,7 @@ JSON Server is an open source tool used to create mock REST APIs. You'll use it
|
||||
"name": "Hopeful Housing Solutions",
|
||||
"city": "Oakland",
|
||||
"state": "CA",
|
||||
"photo": "/assets/r-architecture-GGupkreKwxA-unsplash.jpg",
|
||||
"photo": "https://angular.io/assets/images/tutorials/faa/r-architecture-GGupkreKwxA-unsplash.jpg",
|
||||
"availableUnits": 2,
|
||||
"wifi": true,
|
||||
"laundry": true
|
||||
@@ -113,7 +113,7 @@ JSON Server is an open source tool used to create mock REST APIs. You'll use it
|
||||
"name": "Seriously Safe Towns",
|
||||
"city": "Oakland",
|
||||
"state": "CA",
|
||||
"photo": "/assets/saru-robert-9rP3mxf8qWI-unsplash.jpg",
|
||||
"photo": "https://angular.io/assets/images/tutorials/faa/saru-robert-9rP3mxf8qWI-unsplash.jpg",
|
||||
"availableUnits": 10,
|
||||
"wifi": false,
|
||||
"laundry": false
|
||||
@@ -123,7 +123,7 @@ JSON Server is an open source tool used to create mock REST APIs. You'll use it
|
||||
"name": "Capital Safe Towns",
|
||||
"city": "Portland",
|
||||
"state": "OR",
|
||||
"photo": "/assets/webaliser-_TPTXZd9mOo-unsplash.jpg",
|
||||
"photo": "https://angular.io/assets/images/tutorials/faa/webaliser-_TPTXZd9mOo-unsplash.jpg",
|
||||
"availableUnits": 6,
|
||||
"wifi": true,
|
||||
"laundry": true
|
||||
|
||||
@@ -20,10 +20,7 @@ This tutorial creates a `HeroService` that all application classes can use to ge
|
||||
Instead of creating that service with the [`new` keyword](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/new), use the [*dependency injection*](guide/dependency-injection) that Angular supports to inject it into the `HeroesComponent` constructor.
|
||||
|
||||
Services are a great way to share information among classes that *don't know each other*.
|
||||
Create a `MessageService` next and inject it in these two places.
|
||||
|
||||
* Inject in `HeroService`, which uses the service to send a message
|
||||
* Inject in `MessagesComponent`, which displays that message, and also displays the ID when the user clicks a hero
|
||||
Create a `HeroService` next and inject it in the `HeroesComponent`, to provide hero data.
|
||||
|
||||
## Create the `HeroService`
|
||||
|
||||
|
||||
+15
-15
@@ -61,33 +61,33 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "16.2.0-next.3",
|
||||
"@angular/animations": "16.2.0",
|
||||
"@angular/cdk": "16.2.0-next.4",
|
||||
"@angular/common": "16.2.0-next.3",
|
||||
"@angular/compiler": "16.2.0-next.3",
|
||||
"@angular/core": "16.2.0-next.3",
|
||||
"@angular/elements": "16.2.0-next.3",
|
||||
"@angular/forms": "16.2.0-next.3",
|
||||
"@angular/common": "16.2.0",
|
||||
"@angular/compiler": "16.2.0",
|
||||
"@angular/core": "16.2.0",
|
||||
"@angular/elements": "16.2.0",
|
||||
"@angular/forms": "16.2.0",
|
||||
"@angular/material": "16.2.0-next.4",
|
||||
"@angular/platform-browser": "16.2.0-next.3",
|
||||
"@angular/platform-browser-dynamic": "16.2.0-next.3",
|
||||
"@angular/router": "16.2.0-next.3",
|
||||
"@angular/service-worker": "16.2.0-next.3",
|
||||
"@angular/platform-browser": "16.2.0",
|
||||
"@angular/platform-browser-dynamic": "16.2.0",
|
||||
"@angular/router": "16.2.0",
|
||||
"@angular/service-worker": "16.2.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"safevalues": "^0.4.2",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/architect-cli": "0.1602.0-next.3",
|
||||
"@angular-devkit/build-angular": "16.2.0-next.3",
|
||||
"@angular-devkit/architect-cli": "0.1602.0",
|
||||
"@angular-devkit/build-angular": "16.2.0",
|
||||
"@angular-eslint/builder": "16.0.3",
|
||||
"@angular-eslint/eslint-plugin": "16.0.3",
|
||||
"@angular-eslint/eslint-plugin-template": "16.0.3",
|
||||
"@angular-eslint/template-parser": "^16.0.3",
|
||||
"@angular/build-tooling": "https://github.com/angular/dev-infra-private-build-tooling-builds.git#4463309193594fc8b23090c89c7f34178320681c",
|
||||
"@angular/cli": "16.2.0-next.3",
|
||||
"@angular/compiler-cli": "16.2.0-next.3",
|
||||
"@angular/cli": "16.2.0",
|
||||
"@angular/compiler-cli": "16.2.0",
|
||||
"@bazel/bazelisk": "^1.7.5",
|
||||
"@bazel/buildozer": "^6.0.0",
|
||||
"@bazel/ibazel": "^0.16.2",
|
||||
@@ -100,7 +100,7 @@
|
||||
"@types/trusted-types": "^2.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "5.61.0",
|
||||
"@typescript-eslint/parser": "5.61.0",
|
||||
"archiver": "^5.3.0",
|
||||
"archiver": "^6.0.0",
|
||||
"assert": "^2.0.0",
|
||||
"canonical-path": "1.0.0",
|
||||
"chalk": "^4.1.0",
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
and runs a fast dgeni build on any changed files.
|
||||
*/
|
||||
|
||||
import {createRequire} from 'node:module';
|
||||
import spawn from 'cross-spawn';
|
||||
import watchr from '../tools/transforms/authors-package/watchr.js';
|
||||
import {watch} from '../tools/transforms/authors-package/watchr.js';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const architectCli = require.resolve('@angular-devkit/architect-cli/bin/architect');
|
||||
|
||||
const serve = spawn(
|
||||
@@ -30,4 +33,4 @@ serve.on('close', (code) => {
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
watchr.watch(true);
|
||||
watch(true);
|
||||
|
||||
@@ -5,6 +5,7 @@ set -eu -o pipefail
|
||||
readonly thisDir=$(cd $(dirname $0); pwd)
|
||||
readonly parentDir=$(dirname $thisDir)
|
||||
readonly target=${1:-aio}
|
||||
readonly PROJECT_ROOT=$(realpath "$(dirname ${thisDir})/..")
|
||||
|
||||
# Track payload size functions
|
||||
source ../scripts/ci/payload-size.sh
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user