mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b36d53143a |
@@ -4,7 +4,7 @@ description: 'Installs the dependencies using Yarn'
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4
|
||||
- uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4
|
||||
with:
|
||||
path: |
|
||||
./node_modules/
|
||||
|
||||
@@ -21,16 +21,16 @@ jobs:
|
||||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'adev: preview'))
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev to ensure it continues to work
|
||||
run: yarn bazel build --config=aio_local_deps //adev:build
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
workflow-artifact-name: 'adev-preview'
|
||||
pull-number: '${{github.event.pull_request.number}}'
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
npx -y firebase-tools@latest target:clear --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs
|
||||
npx -y firebase-tools@latest target:apply --config adev/firebase.json --project ${{env.PREVIEW_PROJECT}} hosting angular-docs ${{env.PREVIEW_SITE}}
|
||||
|
||||
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
github-token: '${{secrets.GITHUB_TOKEN}}'
|
||||
workflow-artifact-name: 'adev-preview'
|
||||
|
||||
@@ -16,6 +16,6 @@ jobs:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
- uses: angular/dev-infra/github-actions/branch-manager@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
exit: true
|
||||
|
||||
# Indicate that the benchmark command was received.
|
||||
- uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
|
||||
- uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3
|
||||
with:
|
||||
comment-id: ${{github.event.comment.id}}
|
||||
token: '${{secrets.BENCHMARK_POST_RESULTS_GITHUB_TOKEN}}'
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
|
||||
- uses: ./.github/actions/yarn-install
|
||||
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
bazelrc: ./.bazelrc.user
|
||||
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
id: benchmark
|
||||
name: Running benchmark
|
||||
|
||||
- uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
|
||||
- uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3
|
||||
with:
|
||||
issue-number: ${{github.event.issue.number}}
|
||||
token: '${{secrets.BENCHMARK_POST_RESULTS_GITHUB_TOKEN}}'
|
||||
|
||||
@@ -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@c83e99a12397014162531ca125c94549db55dd84
|
||||
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.event.pull_request.head.sha }}
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@c83e99a12397014162531ca125c94549db55dd84
|
||||
- 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
|
||||
+24
-70
@@ -23,7 +23,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
@@ -58,13 +58,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Run unit tests
|
||||
@@ -76,13 +76,13 @@ jobs:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile --network-timeout 100000
|
||||
- name: Run CI tests for framework
|
||||
@@ -93,11 +93,11 @@ jobs:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev to ensure it continues to work
|
||||
@@ -109,13 +109,13 @@ jobs:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
|
||||
@@ -127,7 +127,7 @@ jobs:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
@@ -135,9 +135,9 @@ jobs:
|
||||
./packages/zone.js/node_modules
|
||||
./packages/zone.js/test/typings/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: |
|
||||
@@ -176,7 +176,7 @@ jobs:
|
||||
JOBS: 2
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
cache-node-modules: true
|
||||
# Checking out the pull request commit is intended here as we need to run the changed code tests.
|
||||
@@ -184,66 +184,20 @@ jobs:
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@50bb71e51d3372ca2e359adb9069f89beeac4ae7
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Set up Sauce Tunnel Daemon
|
||||
run: yarn bazel run //tools/saucelabs-daemon/background-service -- $JOBS &
|
||||
env:
|
||||
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
|
||||
SAUCE_USERNAME: ${{ vars.SAUCE_USERNAME }}
|
||||
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||
- name: Run all saucelabs bazel tests
|
||||
run: |
|
||||
TESTS=$(./node_modules/.bin/bazelisk query --output label '(kind(karma_web_test, ...) intersect attr("tags", "saucelabs", ...)) except attr("tags", "fixme-saucelabs", ...)')
|
||||
yarn bazel test --config=saucelabs --jobs=$JOBS ${TESTS}
|
||||
|
||||
saucelabs:
|
||||
runs-on: ubuntu-latest-4core
|
||||
env:
|
||||
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
with:
|
||||
cache-node-modules: true
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@50bb71e51d3372ca2e359adb9069f89beeac4ae7
|
||||
- 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
|
||||
|
||||
adev-deploy:
|
||||
needs: [adev]
|
||||
if: needs.adev.result == 'success' && github.event_name == 'push' && github.ref_name == 'main'
|
||||
@@ -253,11 +207,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev to ensure it continues to work
|
||||
|
||||
@@ -13,13 +13,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: angular/dev-infra/github-actions/commit-message-based-labels@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
- uses: angular/dev-infra/github-actions/commit-message-based-labels@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
post_approval_changes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
- uses: angular/dev-infra/github-actions/post-approval-changes@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
- uses: angular/dev-infra/github-actions/google-internal-tests@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
run-tests-guide-url: http://go/angular-g3sync-start
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -9,6 +9,6 @@ jobs:
|
||||
status:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
- uses: angular/dev-infra/github-actions/unified-status-check@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -22,15 +22,15 @@ jobs:
|
||||
version: ['https://next.angular.io/', 'https://angular.io/']
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Install node modules in aio
|
||||
run: yarn install --frozen-lockfile --cwd aio
|
||||
- name: Run basic e2e and deployment config tests.
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
|
||||
@@ -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@05963f47d870e2cb19a537396c1f668a348c7d8f # v3.24.8
|
||||
uses: github/codeql-action/upload-sarif@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
env:
|
||||
ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN: ${{ secrets.ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN }}
|
||||
- name: Create a PR (if necessary)
|
||||
uses: angular/dev-infra/github-actions/create-pr-for-changes@1421ff04811ecb45812930c5d1f61d912880e75f
|
||||
uses: angular/dev-infra/github-actions/create-pr-for-changes@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
branch-prefix: update-cli-help
|
||||
pr-title: 'docs: update Angular CLI help [${{github.ref_name}}]'
|
||||
|
||||
+46
-157
@@ -1,176 +1,25 @@
|
||||
<a name="18.0.0-next.1"></a>
|
||||
# 18.0.0-next.1 (2024-03-20)
|
||||
## Breaking Changes
|
||||
### platform-browser-dynamic
|
||||
- No longer used `RESOURCE_CACHE_PROVIDER` APIs have been removed.
|
||||
### platform-server
|
||||
- deprecated `platformDynamicServer` has been removed. Add an `import @angular/compiler` and replace the usage with `platformServer`
|
||||
- deprecated `ServerTransferStateModule` has been removed. `TransferState` can be use without providing this module.
|
||||
- deprecated `useAbsoluteUrl` and `baseUrl` been removed from `PlatformConfig`. Provide and absolute `url` instead.
|
||||
- Legacy handling or Node.js URL parsing has been removed from `ServerPlatformLocation`.
|
||||
|
||||
The main differences are;
|
||||
- `pathname` is always suffixed with a `/`.
|
||||
- `port` is empty when `http:` protocol and port in url is `80`
|
||||
- `port` is empty when `https:` protocol and port in url is `443`
|
||||
### router
|
||||
- This change allows `Route.redirectTo` to be a function
|
||||
in addition to the previous string. Code which expects `redirectTo` to
|
||||
only be a string on `Route` objects will need to be adjusted.
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [879bd80b57](https://github.com/angular/angular/commit/879bd80b571368bdc6e65c5415d98ad0f546267a) | fix | capture data bindings for content projection purposes in blocks ([#54876](https://github.com/angular/angular/pull/54876)) |
|
||||
<a name="17.3.0-rc.0"></a>
|
||||
# 17.3.0-rc.0 (2024-03-06)
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [6aff144232](https://github.com/angular/angular/commit/6aff14423238f8995da8104e60c0baca26df2020) | fix | symbol feature detection for the compiler ([#54711](https://github.com/angular/angular/pull/54711)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [314112de99](https://github.com/angular/angular/commit/314112de99bb97475a0d8bdbddf84a3b3ce4a8fb) | fix | Prevent `markForCheck` during change detection from causing infinite loops ([#54900](https://github.com/angular/angular/pull/54900)) |
|
||||
### platform-browser-dynamic
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [eb20c1a8b1](https://github.com/angular/angular/commit/eb20c1a8b18e2e080c856e3e1bf7bcd02f3bfd28) | refactor | unused `RESOURCE_CACHE_PROVIDER` API has been removed ([#54875](https://github.com/angular/angular/pull/54875)) |
|
||||
### platform-server
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [07ac017731](https://github.com/angular/angular/commit/07ac017731f0e08ea3736f1f212093a28648a304) | refactor | remove deprecated `platformDynamicServer` API ([#54874](https://github.com/angular/angular/pull/54874)) |
|
||||
| [e8b588d8b7](https://github.com/angular/angular/commit/e8b588d8b7fc014aaef99d4b0c1e4567b4aa195d) | refactor | remove deprecated `ServerTransferStateModule` API ([#54874](https://github.com/angular/angular/pull/54874)) |
|
||||
| [3b1967ca64](https://github.com/angular/angular/commit/3b1967ca64479df9137b3ad7a0d04dbaff6496f4) | refactor | remove deprecated `useAbsoluteUrl` and `baseUrl` from `PlatformConfig` ([#54874](https://github.com/angular/angular/pull/54874)) |
|
||||
| [2357d3566c](https://github.com/angular/angular/commit/2357d3566c4d18dc40cbda6644ed459ef7703893) | refactor | remove legacy URL handling logic ([#54874](https://github.com/angular/angular/pull/54874)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [2b802587f2](https://github.com/angular/angular/commit/2b802587f27186baa493c1dd01f42d568b652f38) | feat | Allow Route.redirectTo to be a function which returns a string or UrlTree ([#52606](https://github.com/angular/angular/pull/52606)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.1"></a>
|
||||
# 17.3.1 (2024-03-20)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c0788200e2](https://github.com/angular/angular/commit/c0788200e26406bacb90ee0079ea9753eebd1b32) | fix | capture data bindings for content projection purposes in blocks ([#54876](https://github.com/angular/angular/pull/54876)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [99e9474aa2](https://github.com/angular/angular/commit/99e9474aa2ccccdf4385fbac6b62b1a4585ed4b4) | fix | symbol feature detection for the compiler ([#54711](https://github.com/angular/angular/pull/54711)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="18.0.0-next.0"></a>
|
||||
# 18.0.0-next.0 (2024-03-14)
|
||||
## Breaking Changes
|
||||
### core
|
||||
- `OnPush` views at the root of the application need to
|
||||
be marked dirty for their host bindings to refresh. Previously, the host
|
||||
bindings were refreshed for all root views without respecting the
|
||||
`OnPush` change detection strategy.
|
||||
- The `ComponentFixture` `autoDetect` feature will no
|
||||
longer refresh the component's host view when the component is `OnPush`
|
||||
and not marked dirty. This exposes existing issues in components which
|
||||
claim to be `OnPush` but do not correctly call `markForCheck` when they
|
||||
need to be refreshed. If this change causes test failures, the easiest
|
||||
fix is to change the component to `ChangeDetectionStrategy.Default`.
|
||||
- When Angular runs change detection, it will continue to
|
||||
refresh any views attached to `ApplicationRef` that are still marked for
|
||||
check after one round completes. In rare cases, this can result in infinite
|
||||
loops when certain patterns continue to mark views for check using
|
||||
`ChangeDetectorRef.detectChanges`. This will be surfaced as a runtime
|
||||
error with the `NG0103` code.
|
||||
- The `ComponentFixture.autoDetect` feature now executes
|
||||
change detection for the fixture within `ApplicationRef.tick`. This more
|
||||
closely matches the behavior of how a component would refresh in
|
||||
production. The order of component refresh in tests may be slightly
|
||||
affected as a result, especially when dealing with additional components
|
||||
attached to the application, such as dialogs. Tests sensitive to this
|
||||
type of change (such as screenshot tests) may need to be updated.
|
||||
Concretely, this change means that the component will refresh _before_
|
||||
additional views attached to `ApplicationRef` (i.e. dialog components).
|
||||
Prior to this change, the fixture component would refresh _after_ other
|
||||
views attached to the application.
|
||||
- The exact timing of change detection execution when
|
||||
using event or run coalescing with `NgZone` is now the first of either
|
||||
`setTimeout` or `requestAnimationFrame`. Code which relies on this
|
||||
timing (usually by accident) will need to be adjusted. If a callback
|
||||
needs to execute after change detection, we recommend `afterNextRender`
|
||||
instead of something like `setTimeout`.
|
||||
- Newly created and views marked for check and reattached
|
||||
during change detection are now guaranteed to be refreshed in that same
|
||||
change detection cycle. Previously, if they were attached at a location
|
||||
in the view tree that was already checked, they would either throw
|
||||
`ExpressionChangedAfterItHasBeenCheckedError` or not be refreshed until
|
||||
some future round of change detection. In rare circumstances, this
|
||||
correction can cause issues. We identified one instance that relied on
|
||||
the previous behavior by reading a value on initialization which was
|
||||
queued to be updated in a microtask instead of being available in the
|
||||
current change detection round. The component only read this value during
|
||||
initialization and did not read it again after the microtask updated it.
|
||||
### router
|
||||
- Guards can now return `RedirectCommand` for redirects
|
||||
in addition to `UrlTree`. Code which expects only `boolean` or `UrlTree`
|
||||
values in `Route` types will need to be adjusted.
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [9b424d7224](https://github.com/angular/angular/commit/9b424d7224db46edb16c81979c7e231d5e3db5e9) | fix | preserve original reference to non-deferrable dependency ([#54759](https://github.com/angular/angular/pull/54759)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [64f870c12b](https://github.com/angular/angular/commit/64f870c12bae1ad66509f0d65f8d3e051aae6eaa) | fix | `ApplicationRef.tick` should respect OnPush for host bindings ([#53718](https://github.com/angular/angular/pull/53718)) ([#53718](https://github.com/angular/angular/pull/53718)) |
|
||||
| [8cad4e8cbe](https://github.com/angular/angular/commit/8cad4e8cbe2baf20dae7b7ef1f4253a4940cbba0) | fix | `ComponentFixture` `autoDetect` respects `OnPush` flag of host view ([#54824](https://github.com/angular/angular/pull/54824)) |
|
||||
| [ba8e465974](https://github.com/angular/angular/commit/ba8e46597435a827670f10b971b2c58f7033b180) | fix | Change Detection will continue to refresh views while marked for check ([#54734](https://github.com/angular/angular/pull/54734)) |
|
||||
| [24bc0ed4f2](https://github.com/angular/angular/commit/24bc0ed4f2de47bd998338d73cba394fb45dd497) | fix | ComponentFixture autodetect should detect changes within ApplicationRef.tick ([#54733](https://github.com/angular/angular/pull/54733)) |
|
||||
| [10c5cdb49c](https://github.com/angular/angular/commit/10c5cdb49c51c95086febd37f4d88a9b944d7e1c) | fix | ensure change detection runs in a reasonable timeframe with zone coalescing ([#54578](https://github.com/angular/angular/pull/54578)) |
|
||||
| [ad045efd4b](https://github.com/angular/angular/commit/ad045efd4b1565e01c14399998143538ebfbfd99) | fix | Ensure views marked for check are refreshed during change detection ([#54735](https://github.com/angular/angular/pull/54735)) |
|
||||
| [700c0520bb](https://github.com/angular/angular/commit/700c0520bb638952ba41a8d8260cf12afb078c0e) | fix | Update ApplicationRef.tick loop to only throw in dev mode ([#54848](https://github.com/angular/angular/pull/54848)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8735af08b9](https://github.com/angular/angular/commit/8735af08b976b30cf236a83f9e8b64b5ff62e9f3) | feat | Add ability to return `UrlTree` with `NavigationBehaviorOptions` from guards ([#45023](https://github.com/angular/angular/pull/45023)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.0"></a>
|
||||
# 17.3.0 (2024-03-13)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [1a6beae8a2](https://github.com/angular/angular/commit/1a6beae8a2bdcff27d4c1e402f98246a52247906) | feat | Enable template pipeline by default. ([#54571](https://github.com/angular/angular/pull/54571)) |
|
||||
| [f386a04c9d](https://github.com/angular/angular/commit/f386a04c9ddc2951c8105d5cafcce7b4bedea569) | fix | handle two-way bindings to signal-based template variables in instruction generation ([#54714](https://github.com/angular/angular/pull/54714)) |
|
||||
| [1f129f114e](https://github.com/angular/angular/commit/1f129f114edb21137d74471dd6b652848d2ffb68) | fix | not catching for loop empty tracking expressions ([#54772](https://github.com/angular/angular/pull/54772)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [12dc4d074e](https://github.com/angular/angular/commit/12dc4d074e63edaff626003ad6136a8d122b2ba6) | fix | account for as expression in docs extraction ([#54414](https://github.com/angular/angular/pull/54414)) |
|
||||
| [da7fbb40f0](https://github.com/angular/angular/commit/da7fbb40f06e6e37504f69e7b335f8219f424de2) | fix | detect when the linker is working in unpublished angular and widen supported versions ([#54439](https://github.com/angular/angular/pull/54439)) |
|
||||
| [492e03f699](https://github.com/angular/angular/commit/492e03f699ca95df4cf854885253f63a5a1fb5c1) | fix | flag two-way bindings to non-signal values in templates ([#54714](https://github.com/angular/angular/pull/54714)) |
|
||||
| [5afa4f0ec1](https://github.com/angular/angular/commit/5afa4f0ec1b64b88ef875d48bd143e0f36e0a955) | fix | support `ModuleWithProviders` literal detection with `typeof` ([#54650](https://github.com/angular/angular/pull/54650)) |
|
||||
| [ae7dbe42de](https://github.com/angular/angular/commit/ae7dbe42de5779e578fb636938699b8ba85b33f6) | fix | unwrap expressions with type parameters in query read property ([#54647](https://github.com/angular/angular/pull/54647)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [331b16efd2](https://github.com/angular/angular/commit/331b16efd2f5af876e6dc0ad2474ee7a87b00de5) | feat | add API to inject attributes on the host node ([#54604](https://github.com/angular/angular/pull/54604)) |
|
||||
| [fb540e169a](https://github.com/angular/angular/commit/fb540e169a78a61f38d611f538eea8fdb0971f1d) | feat | add migration for invalid two-way bindings ([#54630](https://github.com/angular/angular/pull/54630)) |
|
||||
| [c687b8f453](https://github.com/angular/angular/commit/c687b8f4531252cd1c3dfbb9a7bd42bdbe666a36) | feat | expose new `output()` API ([#54650](https://github.com/angular/angular/pull/54650)) |
|
||||
| [c809069f21](https://github.com/angular/angular/commit/c809069f213244afd0e2d803a6a43510b218e6f5) | feat | introduce `outputFromObservable()` interop function ([#54650](https://github.com/angular/angular/pull/54650)) |
|
||||
| [aff65fd1f4](https://github.com/angular/angular/commit/aff65fd1f4a61ed76a6f9b623852f197eb3500e4) | feat | introduce `outputToObservable` interop helper ([#54650](https://github.com/angular/angular/pull/54650)) |
|
||||
| [974958913c](https://github.com/angular/angular/commit/974958913ca632971f878a045537472f2c99c665) | feat | support TypeScript 5.4 ([#54414](https://github.com/angular/angular/pull/54414)) |
|
||||
| [39a50f9a8d](https://github.com/angular/angular/commit/39a50f9a8df5afc4968d18924f3d9d7d6b649d3a) | fix | ensure all initializer functions run in an injection context ([#54761](https://github.com/angular/angular/pull/54761)) |
|
||||
| [243ccce624](https://github.com/angular/angular/commit/243ccce62475ae03a2e727d2b3cb2d51a595c4a7) | fix | exclude class attribute intended for projection matching from directive matching ([#54800](https://github.com/angular/angular/pull/54800)) |
|
||||
| [2909e9817d](https://github.com/angular/angular/commit/2909e9817daf69b6478d7d09229491a9a48cff16) | fix | prevent infinite loops in clobbered elements check ([#54425](https://github.com/angular/angular/pull/54425)) |
|
||||
| [33a6fab094](https://github.com/angular/angular/commit/33a6fab094205cc74aceb916e45c8afa22293cf4) | fix | apply TestBed provider overrides to `@defer` dependencies ([#54667](https://github.com/angular/angular/pull/54667)) |
|
||||
| [78e69117f0](https://github.com/angular/angular/commit/78e69117f07e8ae11aab3abe0343df815b3649be) | fix | generic inference for signal inputs may break with `--strictFunctionTypes` ([#54652](https://github.com/angular/angular/pull/54652)) |
|
||||
| [7243c704cf](https://github.com/angular/angular/commit/7243c704cf8a4986fae419793027458e142658f0) | fix | return a readonly signal on `asReadonly`. ([#54706](https://github.com/angular/angular/pull/54706)) |
|
||||
| [bb35414a38](https://github.com/angular/angular/commit/bb35414a38f8a8447d03c66dc5bf60b84409f9e3) | perf | speed up retrieval of `DestroyRef` in `EventEmitter` ([#54748](https://github.com/angular/angular/pull/54748)) |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [8d37ed035c](https://github.com/angular/angular/commit/8d37ed035c9e9796ba9a7b1f055404ea220dbb3b) | fix | exclude caching for authenticated HTTP requests ([#54746](https://github.com/angular/angular/pull/54746)) |
|
||||
| [ffad7b8ea9](https://github.com/angular/angular/commit/ffad7b8ea9d1286ddb3ee7a2dac7dd33fd76b3aa) | fix | untrack various core operations ([#54614](https://github.com/angular/angular/pull/54614)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [c1c7384e02](https://github.com/angular/angular/commit/c1c7384e02becc623c6a42985f7178ca98137264) | feat | Add reusable types for router guards ([#54580](https://github.com/angular/angular/pull/54580)) |
|
||||
| [7225485311](https://github.com/angular/angular/commit/722548531108e247660ebe6966b99b57d510b615) | fix | Navigations triggered by cancellation events should cancel previous navigation ([#54710](https://github.com/angular/angular/pull/54710)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
@@ -214,6 +63,46 @@
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.0-next.1"></a>
|
||||
# 17.3.0-next.1 (2024-02-27)
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [707bfc9b32](https://github.com/angular/angular/commit/707bfc9b326f321f302dccfdfebef7380c914eb5) | perf | `AsyncPipe` should not call `markForCheck` on subscription ([#54554](https://github.com/angular/angular/pull/54554)) |
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [1a6beae8a2](https://github.com/angular/angular/commit/1a6beae8a2bdcff27d4c1e402f98246a52247906) | feat | Enable template pipeline by default. ([#54571](https://github.com/angular/angular/pull/54571)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [12dc4d074e](https://github.com/angular/angular/commit/12dc4d074e63edaff626003ad6136a8d122b2ba6) | fix | account for as expression in docs extraction ([#54414](https://github.com/angular/angular/pull/54414)) |
|
||||
| [f578889ca2](https://github.com/angular/angular/commit/f578889ca2dbb22f2e050d4c4af6aa2d597bf70d) | fix | catch function instance properties in interpolated signal diagnostic ([#54325](https://github.com/angular/angular/pull/54325)) |
|
||||
| [f04ecc0cda](https://github.com/angular/angular/commit/f04ecc0cdaeb3a292a748b1ccc94ce70a573fc79) | fix | identify aliased initializer functions ([#54480](https://github.com/angular/angular/pull/54480)) |
|
||||
| [f5c566c079](https://github.com/angular/angular/commit/f5c566c0793eacf9ca146c8a6b8da15b0e8f4c4d) | fix | identify aliased initializer functions ([#54609](https://github.com/angular/angular/pull/54609)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [331b16efd2](https://github.com/angular/angular/commit/331b16efd2f5af876e6dc0ad2474ee7a87b00de5) | feat | add API to inject attributes on the host node ([#54604](https://github.com/angular/angular/pull/54604)) |
|
||||
| [974958913c](https://github.com/angular/angular/commit/974958913ca632971f878a045537472f2c99c665) | feat | support TypeScript 5.4 ([#54414](https://github.com/angular/angular/pull/54414)) |
|
||||
| [dcb9deb363](https://github.com/angular/angular/commit/dcb9deb3631ff4e839f738f2fb97ca6b894256ef) | fix | collect providers from NgModules while rendering `@defer` block ([#52881](https://github.com/angular/angular/pull/52881)) |
|
||||
| [ff40c9f762](https://github.com/angular/angular/commit/ff40c9f762b2c14870ac2859201ece9660087e79) | fix | fix typo in injectors.svg file ([#54596](https://github.com/angular/angular/pull/54596)) |
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [71e0c7df69](https://github.com/angular/angular/commit/71e0c7df695f274a54d5ffb9dfc0587d06d3a953) | fix | resolve infinite loop for a single line element with a long tag name and angle bracket on a new line ([#54588](https://github.com/angular/angular/pull/54588)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.0-next.0"></a>
|
||||
# 17.3.0-next.0 (2024-02-21)
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [da7fbb40f0](https://github.com/angular/angular/commit/da7fbb40f06e6e37504f69e7b335f8219f424de2) | fix | detect when the linker is working in unpublished angular and widen supported versions ([#54439](https://github.com/angular/angular/pull/54439)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.2.2"></a>
|
||||
# 17.2.2 (2024-02-21)
|
||||
### common
|
||||
|
||||
@@ -206,10 +206,10 @@ cldr_xml_data_repository(
|
||||
# sass rules
|
||||
http_archive(
|
||||
name = "io_bazel_rules_sass",
|
||||
sha256 = "5633816e996a79c77f44306f6228b9ef18fc2ecb412d63b4e314a132225facba",
|
||||
strip_prefix = "rules_sass-79bd239ce77c101ea1aed575678020bd2999f17d",
|
||||
sha256 = "974f5e14c54d300ca63a67910ebfcea6d838d8811fefc61184f2872107152705",
|
||||
strip_prefix = "rules_sass-888dd9c02709e228b60a8b3e51e2b16b2ca5279d",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/rules_sass/archive/79bd239ce77c101ea1aed575678020bd2999f17d.zip",
|
||||
"https://github.com/bazelbuild/rules_sass/archive/888dd9c02709e228b60a8b3e51e2b16b2ca5279d.zip",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
load("//:packages.bzl", "link_packages")
|
||||
load("@npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
|
||||
load("@aio_npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
|
||||
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
|
||||
load("@npm//@angular-devkit/architect-cli:index.bzl", "architect", "architect_test")
|
||||
@@ -73,7 +73,7 @@ APPLICATION_DEPS = link_packages([
|
||||
"@npm//@lezer/highlight",
|
||||
"@npm//@lezer/javascript",
|
||||
"@npm//@lezer/common",
|
||||
"@npm//@xterm/xterm",
|
||||
"@npm//xterm",
|
||||
"@npm//xterm-addon-fit",
|
||||
"@npm//angular-split",
|
||||
])
|
||||
|
||||
@@ -115,7 +115,7 @@ The following steps are executed on project change:
|
||||
5. The previous project dependencies are compared with the new project dependencies.
|
||||
1. If there are differences, a `npm install` is triggered, hiding the preview and going to the install loading step.
|
||||
2. If there are no differences, the project is ready.
|
||||
6. Some states are reset, for example the "reveal answer" state if the previous project was in the "reveal answer" state.
|
||||
6. Some states are resetted, for example the "reveal answer" state if the previous project was in the "reveal answer" state.
|
||||
|
||||
## Components and services
|
||||
|
||||
@@ -200,7 +200,7 @@ Responsible for handling the download button in the embedded editor, fetching th
|
||||
|
||||
#### [`AlertManager`](./alert-manager.service.ts)
|
||||
|
||||
Manage the alerts displayed in the embedded editor, being the out of memory alert when multiple tabs are opened, and unsupported environments alerts.
|
||||
Manage the alerts displayed in the embedded editor, being the out of memory alert when multiple tabs are opened, and unsupported enviroments alerts.
|
||||
|
||||
#### [`TypingsLoader`](./typings-loader.service.ts)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import {inject} from '@angular/core';
|
||||
import {Subject} from 'rxjs';
|
||||
import {Terminal} from '@xterm/xterm';
|
||||
import {Terminal} from 'xterm';
|
||||
|
||||
import {WINDOW} from '@angular/docs';
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Terminal} from '@xterm/xterm';
|
||||
import {Terminal} from 'xterm';
|
||||
import {FitAddon} from 'xterm-addon-fit';
|
||||
import {InteractiveTerminal} from './interactive-terminal';
|
||||
|
||||
|
||||
+11
-12
@@ -22,23 +22,22 @@
|
||||
</div>
|
||||
<ul class="adev-reference-list-legend">
|
||||
@for (itemType of itemTypes; track itemType) {
|
||||
<li
|
||||
class="adev-reference-list-legend-item"
|
||||
[class.adev-reference-list-legend-item-active]="type() === itemType"
|
||||
(click)="filterByItemType(itemType)"
|
||||
>
|
||||
<docs-api-item-label [type]="itemType" mode="short" class="docs-api-item-label" />
|
||||
<span class="docs-api-item-label-full">{{ itemType | adevApiLabel : 'full' }}</span>
|
||||
</li>
|
||||
<li
|
||||
class="adev-reference-list-legend-item"
|
||||
[class.adev-reference-list-legend-item-active]="type() === itemType"
|
||||
(click)="filterByItemType(itemType)"
|
||||
>
|
||||
<docs-api-item-label [type]="itemType" mode="short" class="docs-api-item-label" />
|
||||
<span>{{ itemType | adevApiLabel : 'full' }}</span>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</form>
|
||||
|
||||
@if (featuredGroup().items.length) {
|
||||
<adev-api-items-section [group]="featuredGroup()" class="adev-featured-list" />
|
||||
}
|
||||
@for (group of filteredGroups(); track group) {
|
||||
<adev-api-items-section [group]="group" />
|
||||
<adev-api-items-section [group]="featuredGroup()" class="adev-featured-list" />
|
||||
} @for (group of filteredGroups(); track group) {
|
||||
<adev-api-items-section [group]="group" />
|
||||
}
|
||||
|
||||
<span id="deprecated-description" class="docs-deprecated-description">Deprecated</span>
|
||||
|
||||
@@ -99,7 +99,3 @@
|
||||
.docs-deprecated-description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.docs-api-item-label-full {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -19,5 +19,4 @@ export enum ApiItemType {
|
||||
PIPE = 'pipe',
|
||||
NG_MODULE = 'ng_module',
|
||||
TYPE_ALIAS = 'type_alias',
|
||||
INITIALIZER_API_FUNCTION = 'initializer_api_function',
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import {Pipe, PipeTransform} from '@angular/core';
|
||||
|
||||
import {ApiItemType} from '../interfaces/api-item-type';
|
||||
|
||||
@Pipe({
|
||||
@@ -28,7 +27,6 @@ export class ApiLabel implements PipeTransform {
|
||||
[ApiItemType.PIPE]: 'P',
|
||||
[ApiItemType.NG_MODULE]: 'M',
|
||||
[ApiItemType.TYPE_ALIAS]: 'T',
|
||||
[ApiItemType.INITIALIZER_API_FUNCTION]: 'IA',
|
||||
};
|
||||
|
||||
private readonly fullLabelsMap: Record<ApiItemType, string> = {
|
||||
@@ -44,7 +42,6 @@ export class ApiLabel implements PipeTransform {
|
||||
[ApiItemType.PIPE]: 'Pipe',
|
||||
[ApiItemType.NG_MODULE]: 'Module',
|
||||
[ApiItemType.TYPE_ALIAS]: 'Type Alias',
|
||||
[ApiItemType.INITIALIZER_API_FUNCTION]: 'Initializer API',
|
||||
};
|
||||
|
||||
transform(value: ApiItemType, labelType: 'short' | 'full'): string {
|
||||
|
||||
@@ -41,7 +41,7 @@ class FakeDocViewer {
|
||||
@Input('documentFilePath') documentFilePath: string | undefined;
|
||||
}
|
||||
|
||||
// TODO: export this class, it's a helpful mock we could you on other tests.
|
||||
// TODO: export this class, it's a helpfull mock we could you on other tests.
|
||||
class FakeNodeRuntimeSandbox {
|
||||
loadingStep = signal(0);
|
||||
previewUrl$ = of();
|
||||
|
||||
@@ -17,16 +17,16 @@ Use attribute binding template syntax to control the values of accessibility-rel
|
||||
When binding to ARIA attributes in Angular, you must use the `attr.` prefix. The ARIA specification depends specifically on HTML attributes rather than properties of DOM elements.
|
||||
|
||||
<docs-code language="html">
|
||||
<!-- Use attr. when binding to an ARIA attribute -->
|
||||
<button [attr.aria-label]="myActionLabel">…</button>
|
||||
<!-- Use attr. when binding to an ARIA attribute -->
|
||||
<button [attr.aria-label]="myActionLabel">…</button>
|
||||
</docs-code>
|
||||
|
||||
Note: This syntax is only necessary for attribute *bindings*.
|
||||
Static ARIA attributes require no extra syntax.
|
||||
|
||||
<docs-code language="html">
|
||||
<!-- Static ARIA attributes require no extra syntax -->
|
||||
<button aria-label="Save document">…</button>
|
||||
<!-- Static ARIA attributes require no extra syntax -->
|
||||
<button aria-label="Save document">…</button>
|
||||
</docs-code>
|
||||
|
||||
HELPFUL: By convention, HTML attributes use lowercase names \(`tabindex`\), while properties use camelCase names \(`tabIndex`\).
|
||||
@@ -103,8 +103,8 @@ The following example shows how to find and focus the main content header in the
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {
|
||||
const mainHeader = document.querySelector('#main-content-header')
|
||||
router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {
|
||||
const mainHeader = document.querySelector('#main-content-header')
|
||||
if (mainHeader) {
|
||||
mainHeader.focus();
|
||||
}
|
||||
|
||||
@@ -151,14 +151,14 @@ Consistent conventions make it easy to quickly identify and reference assets of
|
||||
|
||||
| Symbol name | File name |
|
||||
|:--- |:--- |
|
||||
| <docs-code hideCopy language="typescript"> @Component({ … }) <br>export class AppComponent { } </docs-code> | app.component.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Component({ … }) <br>export class HeroesComponent { } </docs-code> | heroes.component.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Component({ … }) <br>export class HeroListComponent { } </docs-code> | hero-list.component.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Component({ … }) <br>export class HeroDetailComponent { } </docs-code> | hero-detail.component.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Directive({ … }) <br>export class ValidationDirective { } </docs-code> | validation.directive.ts |
|
||||
| <docs-code hideCopy language="typescript"> @NgModule({ … }) <br>export class AppModule </docs-code> | app.module.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Pipe({ name: 'initCaps' }) <br>export class InitCapsPipe implements PipeTransform { } </docs-code> | init-caps.pipe.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Injectable() <br>export class UserProfileService { } </docs-code> | user-profile.service.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Component({ … }) 
export class AppComponent { } </docs-code> | app.component.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Component({ … }) 
export class HeroesComponent { } </docs-code> | heroes.component.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Component({ … }) 
export class HeroListComponent { } </docs-code> | hero-list.component.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Component({ … }) 
export class HeroDetailComponent { } </docs-code> | hero-detail.component.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Directive({ … }) 
export class ValidationDirective { } </docs-code> | validation.directive.ts |
|
||||
| <docs-code hideCopy language="typescript"> @NgModule({ … }) 
export class AppModule </docs-code> | app.module.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Pipe({ name: 'initCaps' }) 
export class InitCapsPipe implements PipeTransform { } </docs-code> | init-caps.pipe.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Injectable() 
export class UserProfileService { } </docs-code> | user-profile.service.ts |
|
||||
|
||||
### Service names
|
||||
|
||||
@@ -186,9 +186,9 @@ Service names such as `Credit` are nouns and require a suffix and should be name
|
||||
|
||||
| Symbol name | File name |
|
||||
|:--- |:--- |
|
||||
| <docs-code hideCopy language="typescript"> @Injectable() <br>export class HeroDataService { } </docs-code> | hero-data.service.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Injectable() <br>export class CreditService { } </docs-code> | credit.service.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Injectable() <br>export class Logger { } </docs-code> | logger.service.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Injectable() 
export class HeroDataService { } </docs-code> | hero-data.service.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Injectable() 
export class CreditService { } </docs-code> | credit.service.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Injectable() 
export class Logger { } </docs-code> | logger.service.ts |
|
||||
|
||||
### Bootstrapping
|
||||
|
||||
@@ -293,8 +293,8 @@ Provides a consistent way to quickly identify and reference pipes.
|
||||
|
||||
| Symbol name | File name |
|
||||
|:--- |:--- |
|
||||
| <docs-code hideCopy language="typescript"> @Pipe({ standalone: true, name: 'ellipsis' }) <br>export class EllipsisPipe implements PipeTransform { } </docs-code> | ellipsis.pipe.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Pipe({ standalone: true, name: 'initCaps' }) <br>export class InitCapsPipe implements PipeTransform { } </docs-code> | init-caps.pipe.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Pipe({ standalone: true, name: 'ellipsis' }) 
export class EllipsisPipe implements PipeTransform { } </docs-code> | ellipsis.pipe.ts |
|
||||
| <docs-code hideCopy language="typescript"> @Pipe({ standalone: true, name: 'initCaps' }) 
export class InitCapsPipe implements PipeTransform { } </docs-code> | init-caps.pipe.ts |
|
||||
|
||||
### Unit test file names
|
||||
|
||||
@@ -354,40 +354,40 @@ project root
|
||||
├── src
|
||||
│ ├── app
|
||||
│ │ ├── core
|
||||
│ │ │ └── exception.service.ts|spec.ts
|
||||
│ │ │ └── user-profile.service.ts|spec.ts
|
||||
│ │ │ └── exception.service.ts|spec.ts
|
||||
│ │ │ └── user-profile.service.ts|spec.ts
|
||||
│ │ ├── heroes
|
||||
│ │ │ ├── hero
|
||||
│ │ │ │ └── hero.component.ts|html|css|spec.ts
|
||||
│ │ │ │ └── hero.component.ts|html|css|spec.ts
|
||||
│ │ │ ├── hero-list
|
||||
│ │ │ │ └── hero-list.component.ts|html|css|spec.ts
|
||||
│ │ │ │ └── hero-list.component.ts|html|css|spec.ts
|
||||
│ │ │ ├── shared
|
||||
│ │ │ │ └── hero-button.component.ts|html|css|spec.ts
|
||||
│ │ │ │ └── hero-button.component.ts|html|css|spec.ts
|
||||
│ │ │ │ └── hero.model.ts
|
||||
│ │ │ │ └── hero.service.ts|spec.ts
|
||||
│ │ │ └── heroes.component.ts|html|css|spec.ts
|
||||
│ │ │ │ └── hero.service.ts|spec.ts
|
||||
│ │ │ └── heroes.component.ts|html|css|spec.ts
|
||||
│ │ │ └── heroes.routes.ts
|
||||
│ │ ├── shared
|
||||
│ │ │ └── init-caps.pipe.ts|spec.ts
|
||||
│ │ │ └── filter-text.component.ts|spec.ts
|
||||
│ │ │ └── filter-text.service.ts|spec.ts
|
||||
│ │ │ └── init-caps.pipe.ts|spec.ts
|
||||
│ │ │ └── filter-text.component.ts|spec.ts
|
||||
│ │ │ └── filter-text.service.ts|spec.ts
|
||||
│ │ ├── villains
|
||||
│ │ │ ├── villain
|
||||
│ │ │ │ └── …
|
||||
│ │ │ │ └── …
|
||||
│ │ │ ├── villain-list
|
||||
│ │ │ │ └── …
|
||||
│ │ │ │ └── …
|
||||
│ │ │ ├── shared
|
||||
│ │ │ │ └── …
|
||||
│ │ │ └── villains.component.ts|html|css|spec.ts
|
||||
│ │ │ │ └── …
|
||||
│ │ │ └── villains.component.ts|html|css|spec.ts
|
||||
│ │ │ └── villains.module.ts
|
||||
│ │ │ └── villains-routing.module.ts
|
||||
│ │ └── app.component.ts|html|css|spec.ts
|
||||
│ │ └── app.component.ts|html|css|spec.ts
|
||||
│ │ └── app.routes.ts
|
||||
│ └── main.ts
|
||||
│ └── index.html
|
||||
│ └── …
|
||||
└── node_modules/…
|
||||
└── …
|
||||
│ └── …
|
||||
└── node_modules/…
|
||||
└── …
|
||||
```
|
||||
|
||||
HELPFUL: While components in dedicated folders are widely preferred, another option for small applications is to keep components flat \(not in a dedicated folder\).
|
||||
@@ -506,15 +506,15 @@ project root
|
||||
├──├──app
|
||||
├──├──├── shared
|
||||
├──├──├──└── shared.module.ts
|
||||
├──├──├──└── init-caps.pipe.ts|spec.ts
|
||||
├──├──├──└── filter-text.component.ts|spec.ts
|
||||
├──├──├──└── filter-text.service.ts|spec.ts
|
||||
├──├──└── app.component.ts|html|css|spec.ts
|
||||
├──├──├──└── init-caps.pipe.ts|spec.ts
|
||||
├──├──├──└── filter-text.component.ts|spec.ts
|
||||
├──├──├──└── filter-text.service.ts|spec.ts
|
||||
├──├──└── app.component.ts|html|css|spec.ts
|
||||
├──├──└── app.module.ts
|
||||
├──├──└── app-routing.module.ts
|
||||
├──└── main.ts
|
||||
├──└── index.html
|
||||
└── …
|
||||
└── …
|
||||
```
|
||||
|
||||
<docs-code-multifile>
|
||||
@@ -761,7 +761,7 @@ An element may have more than one attribute directive applied.
|
||||
**Do** be consistent in your choice.
|
||||
|
||||
**Why**? <br />
|
||||
The property associated with `@HostBinding` or the method associated with `@HostListener` can be modified only in a single place —in the directive's class.
|
||||
The property associated with `@HostBinding` or the method associated with `@HostListener` can be modified only in a single place —in the directive's class.
|
||||
If you use the `host` metadata property, you must modify both the property/method declaration in the directive's class and the metadata in the decorator associated with the directive.
|
||||
|
||||
<docs-code header="app/shared/validator.directive.ts" path="adev/src/content/examples/styleguide/src/06-03/app/shared/validator.directive.ts"/>
|
||||
@@ -811,7 +811,7 @@ In this scenario it would be better to provide the service at the component leve
|
||||
|
||||
<docs-code header="src/app/treeshaking/service.ts" path="adev/src/content/examples/dependency-injection/src/app/tree-shaking/service.ts"/>
|
||||
|
||||
### Use the @Injectable() class decorator
|
||||
### Use the @Injectable() class decorator
|
||||
|
||||
#### Style 07-04
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Keeping your Angular application up-to-date enables you to take advantage of lea
|
||||
|
||||
This document contains information and resources to help you keep your Angular applications and libraries up-to-date.
|
||||
|
||||
For information about our versioning policy and practices —including support and deprecation practices, as well as the release schedule— see [Angular versioning and releases](reference/releases "Angular versioning and releases").
|
||||
For information about our versioning policy and practices —including support and deprecation practices, as well as the release schedule— see [Angular versioning and releases](reference/releases "Angular versioning and releases").
|
||||
|
||||
HELPFUL: If you are currently using AngularJS, see [Upgrading from AngularJS](https://angular.io/guide/upgrade "Upgrading from Angular JS").
|
||||
*AngularJS* is the name for all v1.x versions of Angular.
|
||||
|
||||
@@ -33,7 +33,7 @@ After running this command you can see that the `angular.json` configuration fil
|
||||
<docs-code language="json">
|
||||
|
||||
"server": {
|
||||
"builder": "@angular-devkit/build-angular:server",
|
||||
"builder": "@angular-devkit/build-angular:server",
|
||||
"defaultConfiguration": "production",
|
||||
"options": {
|
||||
"outputPath": "dist/my-app/server",
|
||||
@@ -58,7 +58,7 @@ After running this command you can see that the `angular.json` configuration fil
|
||||
}
|
||||
},
|
||||
"app-shell": {
|
||||
"builder": "@angular-devkit/build-angular:app-shell",
|
||||
"builder": "@angular-devkit/build-angular:app-shell",
|
||||
"defaultConfiguration": "production",
|
||||
"options": {
|
||||
"route": "shell"
|
||||
|
||||
@@ -28,7 +28,7 @@ The `versionUpdates` is an `Observable` property of `SwUpdate` and emits four ev
|
||||
### Checking for updates
|
||||
|
||||
It's possible to ask the service worker to check if any updates have been deployed to the server.
|
||||
The service worker checks for updates during initialization and on each navigation request —that is, when the user navigates from a different address to your application.
|
||||
The service worker checks for updates during initialization and on each navigation request —that is, when the user navigates from a different address to your application.
|
||||
However, you might choose to manually check for updates if you have a site that changes frequently or want updates to happen on a schedule.
|
||||
|
||||
Do this with the `checkForUpdate()` method:
|
||||
|
||||
@@ -7,7 +7,7 @@ This topic describes the properties of the service worker configuration file.
|
||||
The `ngsw-config.json` JSON configuration file specifies which files and data URLs the Angular service worker should cache and how it should update the cached files and data.
|
||||
The [Angular CLI](tools/cli) processes this configuration file during `ng build`.
|
||||
|
||||
All file paths must begin with `/`, which corresponds to the deployment directory — usually `dist/<project-name>` in CLI projects.
|
||||
All file paths must begin with `/`, which corresponds to the deployment directory — usually `dist/<project-name>` in CLI projects.
|
||||
|
||||
Unless otherwise commented, patterns use a **limited*** glob format that internally will be converted into regex:
|
||||
|
||||
@@ -68,10 +68,10 @@ This field contains an array of asset groups, each of which defines a set of ass
|
||||
{
|
||||
"assetGroups": [
|
||||
{
|
||||
…
|
||||
…
|
||||
},
|
||||
{
|
||||
…
|
||||
…
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -169,10 +169,10 @@ This field contains an array of data groups, each of which defines a set of data
|
||||
{
|
||||
"dataGroups": [
|
||||
{
|
||||
…
|
||||
…
|
||||
},
|
||||
{
|
||||
…
|
||||
…
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -197,7 +197,7 @@ export interface DataGroup {
|
||||
maxSize: number;
|
||||
maxAge: string;
|
||||
timeout?: string;
|
||||
strategy?: 'freshness' | 'performance';
|
||||
strategy?: 'freshness' | 'performance';
|
||||
};
|
||||
cacheQueryOptions?: {
|
||||
ignoreSearch?: boolean;
|
||||
@@ -226,7 +226,7 @@ Only non-mutating requests (GET and HEAD) are cached.
|
||||
Occasionally APIs change formats in a way that is not backward-compatible.
|
||||
A new version of the application might not be compatible with the old API format and thus might not be compatible with existing cached resources from that API.
|
||||
|
||||
`version` provides a mechanism to indicate that the resources being cached have been updated in a backwards-incompatible way, and that the old cache entries —those from previous versions— should be discarded.
|
||||
`version` provides a mechanism to indicate that the resources being cached have been updated in a backwards-incompatible way, and that the old cache entries —those from previous versions— should be discarded.
|
||||
|
||||
`version` is an integer field and defaults to `1`.
|
||||
|
||||
@@ -306,7 +306,7 @@ In case you are not familiar, an [opaque response][https://fetch.spec.whatwg.org
|
||||
One of the characteristics of an opaque response is that the service worker is not allowed to read its status, meaning it can't check if the request was successful or not.
|
||||
See [Introduction to fetch()][https://developers.google.com/web/updates/2015/03/introduction-to-fetch#response_types] for more details.
|
||||
|
||||
If you are not able to implement CORS — for example, if you don't control the origin — prefer using the `freshness` strategy for resources that result in opaque responses.
|
||||
If you are not able to implement CORS — for example, if you don't control the origin — prefer using the `freshness` strategy for resources that result in opaque responses.
|
||||
|
||||
</docs-callout>
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ Clients: 7b79a015-69af-4d3d-9ae6-95ba90c79486, 5bc08295-aaf2-42f3-a4cc-9e4ef9100
|
||||
Last update tick: 1s496u
|
||||
Last update run: never
|
||||
Task queue:
|
||||
* init post-load (update, cleanup)
|
||||
* init post-load (update, cleanup)
|
||||
|
||||
Debug log:
|
||||
|
||||
@@ -232,7 +232,7 @@ HELPFUL: This version hash is the "latest manifest hash" listed above. Both clie
|
||||
Last update tick: 1s496u
|
||||
Last update run: never
|
||||
Task queue:
|
||||
* init post-load (update, cleanup)
|
||||
* init post-load (update, cleanup)
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ To simulate a network issue, disable network interaction for your application.
|
||||
|
||||
In Chrome:
|
||||
|
||||
1. Select **Tools** > **Developer Tools** (from the Chrome menu located in the top right corner).
|
||||
1. Select **Tools** > **Developer Tools** (from the Chrome menu located in the top right corner).
|
||||
1. Go to the **Network tab**.
|
||||
1. Select **Offline** in the **Throttling** dropdown menu.
|
||||
|
||||
@@ -110,7 +110,7 @@ Make a change to the application, and watch the service worker install the updat
|
||||
<docs-code language="shell">
|
||||
|
||||
ng build
|
||||
npx http-server -p 8080 -c-1 dist/<project-name>/browser
|
||||
npx http-server -p 8080 -c-1 dist/<project-name>/browser
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ Invoke push notifications by pushing a message with a valid payload.
|
||||
See `SwPush` for guidance.
|
||||
|
||||
HELPFUL: In Chrome, you can test push notifications without a backend.
|
||||
Open Devtools -> Application -> Service Workers and use the `Push` input to send a JSON notification payload.
|
||||
Open Devtools -> Application -> Service Workers and use the `Push` input to send a JSON notification payload.
|
||||
|
||||
## Notification click handling
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ To add a web worker to an existing project, use the Angular CLI `ng generate` co
|
||||
|
||||
<docs-code language="shell">
|
||||
|
||||
ng generate web-worker <location>
|
||||
ng generate web-worker <location>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -31,8 +31,8 @@ The command performs the following actions.
|
||||
|
||||
<docs-code language="typescript" header="src/app/app.worker.ts">
|
||||
|
||||
addEventListener('message', ({ data }) => {
|
||||
const response = `worker response to ${data}`;
|
||||
addEventListener('message', ({ data }) => {
|
||||
const response = `worker response to ${data}`;
|
||||
postMessage(response);
|
||||
});
|
||||
|
||||
@@ -45,8 +45,8 @@ The command performs the following actions.
|
||||
if (typeof Worker !== 'undefined') {
|
||||
// Create a new
|
||||
const worker = new Worker(new URL('./app.worker', import.meta.url));
|
||||
worker.onmessage = ({ data }) => {
|
||||
console.log(`page got message: ${data}`);
|
||||
worker.onmessage = ({ data }) => {
|
||||
console.log(`page got message: ${data}`);
|
||||
};
|
||||
worker.postMessage('hello');
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
load("//aio/content/examples:examples.bzl", "docs_example")
|
||||
load("@npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
|
||||
load("@aio_npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
load("//aio/content/examples:examples.bzl", "docs_example")
|
||||
load("@npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
|
||||
load("@aio_npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
load("//aio/content/examples:examples.bzl", "docs_example")
|
||||
load("@npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
|
||||
load("@aio_npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
load("//aio/content/examples:examples.bzl", "docs_example")
|
||||
load("@npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
|
||||
load("@aio_npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ HELPFUL: Some additional notes on using styles within [`state`](api/animations/s
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
transition( 'on => off, off => void' )
|
||||
transition( 'on => off, off => void' )
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -227,7 +227,7 @@ Then, you can bind the trigger to a template expression using standard Angular p
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
<div [@triggerName]="expression">…</div>;
|
||||
<div [@triggerName]="expression">…</div>;
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ Adding these styles to the views animates the containers in place and prevents o
|
||||
Use the `query()` method to find and animate elements within the current host component.
|
||||
The `query(":enter")` statement returns the view that is being inserted, and `query(":leave")` returns the view that is being removed.
|
||||
|
||||
Assume that you are routing from the *Home => About*.
|
||||
Assume that you are routing from the *Home => About*.
|
||||
|
||||
<docs-code header="src/app/animations.ts (excerpt)" path="adev/src/content/examples/animations/src/app/animations.ts" visibleRegion="query"/>
|
||||
|
||||
|
||||
@@ -85,8 +85,8 @@ These aliases are used by several animation functions.
|
||||
|
||||
<docs-code hideCopy language="typescript">
|
||||
|
||||
transition ( ':enter', [ … ] ); // alias for void => *
|
||||
transition ( ':leave', [ … ] ); // alias for * => void
|
||||
transition ( ':enter', [ … ] ); // alias for void => *
|
||||
transition ( ':leave', [ … ] ); // alias for * => void
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ The `EnvironmentInjector` can be configured in one of two ways by using:
|
||||
* The `@Injectable()` `providedIn` property to refer to `root` or `platform`
|
||||
* The `ApplicationConfig` `providers` array
|
||||
|
||||
<docs-callout title="Tree-shaking and @Injectable()">
|
||||
<docs-callout title="Tree-shaking and @Injectable()">
|
||||
|
||||
Using the `@Injectable()` `providedIn` property is preferable to using the `ApplicationConfig` `providers` array. With `@Injectable()` `providedIn`, optimization tools can perform tree-shaking, which removes services that your application isn't using. This results in smaller bundle sizes.
|
||||
|
||||
@@ -46,7 +46,7 @@ Provide services using `providedIn` of `@Injectable()` as follows:
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root' // <--provides this service in the root EnvironmentInjector
|
||||
providedIn: 'root' // <--provides this service in the root EnvironmentInjector
|
||||
})
|
||||
export class ItemService {
|
||||
name = 'telephone';
|
||||
@@ -134,7 +134,7 @@ For example, the following `TestComponent` configures the `ElementInjector` by p
|
||||
|
||||
<docs-code language="typescript" highlight="[3]">
|
||||
@Component({
|
||||
…
|
||||
…
|
||||
providers: [{ provide: ItemService, useValue: { name: 'lamp' } }]
|
||||
})
|
||||
export class TestComponent
|
||||
@@ -335,7 +335,7 @@ The following is an example of how the `<app-root>` and `<app-child>` view trees
|
||||
<#VIEW>
|
||||
<app-child>
|
||||
<#VIEW>
|
||||
…content goes here…
|
||||
…content goes here…
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
<#VIEW>
|
||||
@@ -387,24 +387,24 @@ The most basic rendered view would look like nested HTML elements such as the fo
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<app-root> <!-- AppComponent selector -->
|
||||
<app-child> <!-- ChildComponent selector -->
|
||||
</app-child>
|
||||
</app-root>
|
||||
<app-root> <!-- AppComponent selector -->
|
||||
<app-child> <!-- ChildComponent selector -->
|
||||
</app-child>
|
||||
</app-root>
|
||||
|
||||
</docs-code>
|
||||
|
||||
However, behind the scenes, Angular uses a logical view representation as follows when resolving injection requests:
|
||||
|
||||
<docs-code language="html">
|
||||
<app-root> <!-- AppComponent selector -->
|
||||
<#VIEW>
|
||||
<app-child> <!-- ChildComponent selector -->
|
||||
<#VIEW>
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
<app-root> <!-- AppComponent selector -->
|
||||
<#VIEW>
|
||||
<app-child> <!-- ChildComponent selector -->
|
||||
<#VIEW>
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
</docs-code>
|
||||
|
||||
The `<#VIEW>` here represents an instance of a template.
|
||||
@@ -435,16 +435,16 @@ Emoji from FlowerService: 🌺
|
||||
In the logical tree, this would be represented as follows:
|
||||
|
||||
<docs-code language="html" highlight="[[1],[2],[4]]">
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(FlowerService) flower=>"🌺">
|
||||
<#VIEW>
|
||||
<p>Emoji from FlowerService: {{flower.emoji}} (🌺)</p>
|
||||
<app-child>
|
||||
<#VIEW>
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(FlowerService) flower=>"🌺">
|
||||
<#VIEW>
|
||||
<p>Emoji from FlowerService: {{flower.emoji}} (🌺)</p>
|
||||
<app-child>
|
||||
<#VIEW>
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -507,19 +507,19 @@ In the logical tree, this is represented as follows:
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(FlowerService) flower=>"🌺">
|
||||
<#VIEW>
|
||||
<p>Emoji from FlowerService: {{flower.emoji}} (🌺)</p>
|
||||
<app-child @Provide(FlowerService="🌻")
|
||||
@Inject(FlowerService)=>"🌻"> <!-- search ends here -->
|
||||
<#VIEW> <!-- search starts here -->
|
||||
<h2>Child Component</h2>
|
||||
<p>Emoji from FlowerService: {{flower.emoji}} (🌻)</p>
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(FlowerService) flower=>"🌺">
|
||||
<#VIEW>
|
||||
<p>Emoji from FlowerService: {{flower.emoji}} (🌺)</p>
|
||||
<app-child @Provide(FlowerService="🌻")
|
||||
@Inject(FlowerService)=>"🌻"> <!-- search ends here -->
|
||||
<#VIEW> <!-- search starts here -->
|
||||
<h2>Child Component</h2>
|
||||
<p>Emoji from FlowerService: {{flower.emoji}} (🌻)</p>
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -613,18 +613,18 @@ The logic tree for this example of `viewProviders` is as follows:
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(AnimalService) animal=>"🐳">
|
||||
<#VIEW>
|
||||
<app-child>
|
||||
<#VIEW @Provide(AnimalService="🐶")
|
||||
@Inject(AnimalService=>"🐶")>
|
||||
<!-- ^^using viewProviders means AnimalService is available in <#VIEW>-->
|
||||
<p>Emoji from AnimalService: {{animal.emoji}} (🐶)</p>
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(AnimalService) animal=>"🐳">
|
||||
<#VIEW>
|
||||
<app-child>
|
||||
<#VIEW @Provide(AnimalService="🐶")
|
||||
@Inject(AnimalService=>"🐶")>
|
||||
<!-- ^^using viewProviders means AnimalService is available in <#VIEW>-->
|
||||
<p>Emoji from AnimalService: {{animal.emoji}} (🐶)</p>
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -715,31 +715,31 @@ The `AnimalService` in the logical tree would look like this:
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(AnimalService) animal=>"🐳">
|
||||
<#VIEW>
|
||||
<app-child>
|
||||
<#VIEW @Provide(AnimalService="🐶")
|
||||
@Inject(AnimalService=>"🐶")>
|
||||
<!-- ^^using viewProviders means AnimalService is available in <#VIEW>-->
|
||||
<p>Emoji from AnimalService: {{animal.emoji}} (🐶)</p>
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(AnimalService) animal=>"🐳">
|
||||
<#VIEW>
|
||||
<app-child>
|
||||
<#VIEW @Provide(AnimalService="🐶")
|
||||
@Inject(AnimalService=>"🐶")>
|
||||
<!-- ^^using viewProviders means AnimalService is available in <#VIEW>-->
|
||||
<p>Emoji from AnimalService: {{animal.emoji}} (🐶)</p>
|
||||
|
||||
<div class="container">
|
||||
<h3>Content projection</h3>
|
||||
<app-inspector @Inject(AnimalService) animal=>"🐳">
|
||||
<p>Emoji from AnimalService: {{animal.emoji}} (🐳)</p>
|
||||
</app-inspector>
|
||||
</div>
|
||||
<div class="container">
|
||||
<h3>Content projection</h3>
|
||||
<app-inspector @Inject(AnimalService) animal=>"🐳">
|
||||
<p>Emoji from AnimalService: {{animal.emoji}} (🐳)</p>
|
||||
</app-inspector>
|
||||
</div>
|
||||
|
||||
<app-inspector>
|
||||
<#VIEW @Inject(AnimalService) animal=>"🐶">
|
||||
<p>Emoji from AnimalService: {{animal.emoji}} (🐶)</p>
|
||||
</#VIEW>
|
||||
</app-inspector>
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
<app-inspector>
|
||||
<#VIEW @Inject(AnimalService) animal=>"🐶">
|
||||
<p>Emoji from AnimalService: {{animal.emoji}} (🐶)</p>
|
||||
</#VIEW>
|
||||
</app-inspector>
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -773,16 +773,16 @@ In a logical tree, this same idea might look like this:
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(FlowerService) flower=>"🌺">
|
||||
<#VIEW>
|
||||
<app-child @Provide(FlowerService="🌻")>
|
||||
<#VIEW @Inject(FlowerService, SkipSelf)=>"🌺">
|
||||
<!-- With SkipSelf, the injector looks to the next injector up the tree (app-root) -->
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(FlowerService) flower=>"🌺">
|
||||
<#VIEW>
|
||||
<app-child @Provide(FlowerService="🌻")>
|
||||
<#VIEW @Inject(FlowerService, SkipSelf)=>"🌺">
|
||||
<!-- With SkipSelf, the injector looks to the next injector up the tree (app-root) -->
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -794,15 +794,15 @@ Here's the idea in the logical tree:
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(FlowerService) flower=>"🌺">
|
||||
<#VIEW> <!-- end search here with null-->
|
||||
<app-child @Provide(FlowerService="🌻")> <!-- start search here -->
|
||||
<#VIEW @Inject(FlowerService, @SkipSelf, @Host, @Optional)=>null>
|
||||
</#VIEW>
|
||||
</app-parent>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(FlowerService) flower=>"🌺">
|
||||
<#VIEW> <!-- end search here with null-->
|
||||
<app-child @Provide(FlowerService="🌻")> <!-- start search here -->
|
||||
<#VIEW @Inject(FlowerService, @SkipSelf, @Host, @Optional)=>null>
|
||||
</#VIEW>
|
||||
</app-parent>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -820,7 +820,7 @@ Instead, the injector will begin at the `<app-root>` `ElementInjector`.
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'app-child',
|
||||
…
|
||||
…
|
||||
viewProviders: [
|
||||
{ provide: AnimalService, useValue: { emoji: '🐶' } },
|
||||
],
|
||||
@@ -831,17 +831,17 @@ The logical tree looks like this with `@SkipSelf()` in `<app-child>`:
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(AnimalService=>"🐳")>
|
||||
<#VIEW><!-- search begins here -->
|
||||
<app-child>
|
||||
<#VIEW @Provide(AnimalService="🐶")
|
||||
@Inject(AnimalService, SkipSelf=>"🐳")>
|
||||
<!--Add @SkipSelf -->
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(AnimalService=>"🐳")>
|
||||
<#VIEW><!-- search begins here -->
|
||||
<app-child>
|
||||
<#VIEW @Provide(AnimalService="🐶")
|
||||
@Inject(AnimalService, SkipSelf=>"🐳")>
|
||||
<!--Add @SkipSelf -->
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -857,7 +857,7 @@ You can also see `@Host()` in the constructor:
|
||||
@Component({
|
||||
standalone: true
|
||||
selector: 'app-child',
|
||||
…
|
||||
…
|
||||
viewProviders: [
|
||||
{ provide: AnimalService, useValue: { emoji: '🐶' } },
|
||||
]
|
||||
@@ -871,16 +871,16 @@ export class ChildComponent {
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(AnimalService=>"🐳")>
|
||||
<#VIEW>
|
||||
<app-child>
|
||||
<#VIEW @Provide(AnimalService="🐶")
|
||||
@Inject(AnimalService, @Host=>"🐶")> <!-- @Host stops search here -->
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(AnimalService=>"🐳")>
|
||||
<#VIEW>
|
||||
<app-child>
|
||||
<#VIEW @Provide(AnimalService="🐶")
|
||||
@Inject(AnimalService, @Host=>"🐶")> <!-- @Host stops search here -->
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -915,7 +915,7 @@ export class ChildComponent {
|
||||
and how `@Host()` works.
|
||||
-->
|
||||
|
||||
When `@Host()` and `@SkipSelf()` were applied to the `FlowerService`, which is in the `providers` array, the result was `null` because `@SkipSelf()` starts its search in the `<app-child>` injector, but `@Host()` stops searching at `<#VIEW>` —where there is no `FlowerService`
|
||||
When `@Host()` and `@SkipSelf()` were applied to the `FlowerService`, which is in the `providers` array, the result was `null` because `@SkipSelf()` starts its search in the `<app-child>` injector, but `@Host()` stops searching at `<#VIEW>` —where there is no `FlowerService`
|
||||
In the logical tree, you can see that the `FlowerService` is visible in `<app-child>`, not its `<#VIEW>`.
|
||||
|
||||
However, the `AnimalService`, which is provided in the `AppComponent` `viewProviders` array, is visible.
|
||||
@@ -924,19 +924,19 @@ The logical tree representation shows why this is:
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(AnimalService=>"🐳")>
|
||||
<#VIEW @Provide(AnimalService="🦔")
|
||||
@Inject(AnimalService, @Optional)=>"🦔">
|
||||
<!-- ^^@SkipSelf() starts here, @Host() stops here^^ -->
|
||||
<app-child>
|
||||
<#VIEW @Provide(AnimalService="🐶")
|
||||
@Inject(AnimalService, @SkipSelf, @Host, @Optional)=>"🦔">
|
||||
<!-- Add @SkipSelf ^^-->
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
<app-root @ApplicationConfig
|
||||
@Inject(AnimalService=>"🐳")>
|
||||
<#VIEW @Provide(AnimalService="🦔")
|
||||
@Inject(AnimalService, @Optional)=>"🦔">
|
||||
<!-- ^^@SkipSelf() starts here, @Host() stops here^^ -->
|
||||
<app-child>
|
||||
<#VIEW @Provide(AnimalService="🐶")
|
||||
@Inject(AnimalService, @SkipSelf, @Host, @Optional)=>"🦔">
|
||||
<!-- Add @SkipSelf ^^-->
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ This component contains a body and can contain an optional header.
|
||||
<docs-code language="html">
|
||||
|
||||
<lib-card>;
|
||||
<lib-header>…</lib-header>;
|
||||
<lib-header>…</lib-header>;
|
||||
</lib-card>;
|
||||
|
||||
</docs-code>
|
||||
@@ -35,13 +35,13 @@ In a likely implementation, the `<lib-card>` component uses `@ContentChild()` or
|
||||
<docs-code language="typescript" highlight="[12]">
|
||||
@Component({
|
||||
selector: 'lib-header',
|
||||
…,
|
||||
…,
|
||||
})
|
||||
class LibHeaderComponent {}
|
||||
|
||||
@Component({
|
||||
selector: 'lib-card',
|
||||
…,
|
||||
…,
|
||||
})
|
||||
class LibCardComponent {
|
||||
@ContentChild(LibHeaderComponent) header: LibHeaderComponent|null = null;
|
||||
@@ -108,13 +108,13 @@ abstract class LibHeaderToken {}
|
||||
providers: [
|
||||
{provide: LibHeaderToken, useExisting: LibHeaderComponent}
|
||||
]
|
||||
…,
|
||||
…,
|
||||
})
|
||||
class LibHeaderComponent extends LibHeaderToken {}
|
||||
|
||||
@Component({
|
||||
selector: 'lib-card',
|
||||
…,
|
||||
…,
|
||||
})
|
||||
class LibCardComponent {
|
||||
@ContentChild(LibHeaderToken) header: LibHeaderToken|null = null;
|
||||
@@ -156,7 +156,7 @@ abstract class LibHeaderToken {
|
||||
providers: [
|
||||
{provide: LibHeaderToken, useExisting: LibHeaderComponent}
|
||||
]
|
||||
…,
|
||||
…,
|
||||
})
|
||||
class LibHeaderComponent extends LibHeaderToken {
|
||||
doSomething(): void {
|
||||
@@ -166,7 +166,7 @@ class LibHeaderComponent extends LibHeaderToken {
|
||||
|
||||
@Component({
|
||||
selector: 'lib-card',
|
||||
…,
|
||||
…,
|
||||
})
|
||||
class LibCardComponent implement AfterContentInit {
|
||||
@ContentChild(LibHeaderToken) header: LibHeaderToken|null = null;
|
||||
|
||||
@@ -130,7 +130,7 @@ When you write your own structural directives, use the following syntax:
|
||||
|
||||
<docs-code hideCopy language="typescript">
|
||||
|
||||
*:prefix="( :let | :expression ) (';' | ',')? ( :let | :as | :keyExp )*"
|
||||
*:prefix="( :let | :expression ) (';' | ',')? ( :let | :as | :keyExp )*"
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ After you register your configured class with the browser's custom-element regis
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<my-popup message="Use Angular!"></my-popup>
|
||||
<my-popup message="Use Angular!"></my-popup>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -73,7 +73,7 @@ For more information, see Web Component documentation for [Creating custom event
|
||||
|
||||
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.
|
||||
|
||||
Using an Angular custom element makes the process simpler and more transparent, by providing all the infrastructure and framework automatically —all you have to do is define the kind of event handling you want.
|
||||
Using an Angular custom element makes the process simpler and more transparent, by providing all 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.\)
|
||||
|
||||
The following Popup Service example application defines a component that you can either load dynamically or convert to a custom element.
|
||||
@@ -111,9 +111,9 @@ Assume you create a `my-dialog` custom element based on the following component:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@Component(…)
|
||||
@Component(…)
|
||||
class MyDialog {
|
||||
@Input() content: string;
|
||||
@Input() content: string;
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
@@ -123,10 +123,10 @@ For that, use the `NgElement` and `WithProperties` types \(both exported from `@
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
const aDialog = document.createElement('my-dialog') as NgElement & WithProperties<{content: string}>;
|
||||
const aDialog = document.createElement('my-dialog') as NgElement & WithProperties<{content: string}>;
|
||||
aDialog.content = 'Hello, world!';
|
||||
aDialog.content = 123; // <-- ERROR: TypeScript knows this should be a string.
|
||||
aDialog.body = 'News'; // <-- ERROR: TypeScript knows there is no `body` property on `aDialog`.
|
||||
aDialog.content = 123; // <-- ERROR: TypeScript knows this should be a string.
|
||||
aDialog.body = 'News'; // <-- ERROR: TypeScript knows there is no `body` property on `aDialog`.
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -139,9 +139,9 @@ An alternative way, that only requires defining each custom element's type once,
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'my-dialog': NgElement & WithProperties<{content: string}>;
|
||||
'my-other-element': NgElement & WithProperties<{foo: 'bar'}>;
|
||||
…
|
||||
'my-dialog': NgElement & WithProperties<{content: string}>;
|
||||
'my-other-element': NgElement & WithProperties<{foo: 'bar'}>;
|
||||
…
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,9 +151,9 @@ Now, TypeScript can infer the correct type the same way it does for built-in ele
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
document.createElement('div') //--> HTMLDivElement (built-in element)
|
||||
document.querySelector('foo') //--> Element (unknown element)
|
||||
document.createElement('my-dialog') //--> NgElement & WithProperties<{content: string}> (custom element)
|
||||
document.querySelector('my-other-element') //--> NgElement & WithProperties<{foo: 'bar'}> (custom element)
|
||||
document.createElement('div') //--> HTMLDivElement (built-in element)
|
||||
document.querySelector('foo') //--> Element (unknown element)
|
||||
document.createElement('my-dialog') //--> NgElement & WithProperties<{content: string}> (custom element)
|
||||
document.querySelector('my-other-element') //--> NgElement & WithProperties<{foo: 'bar'}> (custom element)
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -42,7 +42,7 @@ The following code from the example shows the setup in the root module.
|
||||
## Create a form object model
|
||||
|
||||
A dynamic form requires an object model that can describe all scenarios needed by the form functionality.
|
||||
The example hero-application form is a set of questions — that is, each control in the form must ask a question and accept an answer.
|
||||
The example hero-application form is a set of questions — that is, each control in the form must ask a question and accept an answer.
|
||||
|
||||
The data model for this type of form must represent a question.
|
||||
The example includes the `DynamicFormQuestionComponent`, which defines a question as the fundamental object in the model.
|
||||
|
||||
@@ -61,11 +61,11 @@ The same built-in validators that are available as attributes in template-driven
|
||||
For a full list of built-in validators, see the [Validators](api/forms/Validators) API reference.
|
||||
|
||||
To update the actor form to be a reactive form, use some of the same
|
||||
built-in validators —this time, in function form, as in the following example.
|
||||
built-in validators —this time, in function form, as in the following example.
|
||||
|
||||
<docs-code header="reactive/actor-form-reactive.component.ts (validator functions)" path="adev/src/content/examples/form-validation/src/app/reactive/actor-form-reactive.component.1.ts" visibleRegion="form-group"/>
|
||||
|
||||
In this example, the `name` control sets up two built-in validators —`Validators.required` and `Validators.minLength(4)`— and one custom validator, `forbiddenNameValidator`.
|
||||
In this example, the `name` control sets up two built-in validators —`Validators.required` and `Validators.minLength(4)`— and one custom validator, `forbiddenNameValidator`.
|
||||
|
||||
All of these validators are synchronous, so they are passed as the second argument.
|
||||
Notice that you can support multiple validators by passing the functions in as an array.
|
||||
@@ -129,7 +129,7 @@ For example:
|
||||
<docs-code header="template/actor-form-template.component.html (forbidden-name-input)" path="adev/src/content/examples/form-validation/src/app/template/actor-form-template.component.html" visibleRegion="name-input"/>
|
||||
|
||||
HELPFUL: Notice that the custom validation directive is instantiated with `useExisting` rather than `useClass`.
|
||||
The registered validator must be *this instance* of the `ForbiddenValidatorDirective` —the instance in the form with its `forbiddenName` property bound to "bob".
|
||||
The registered validator must be *this instance* of the `ForbiddenValidatorDirective` —the instance in the form with its `forbiddenName` property bound to "bob".
|
||||
|
||||
If you were to replace `useExisting` with `useClass`, then you'd be registering a new class instance, one that doesn't have a `forbiddenName`.
|
||||
|
||||
@@ -253,8 +253,8 @@ The following example shows how to achieve this in a template-driven form.
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<input [(ngModel)]="name" #model="ngModel" appSomeAsyncValidator>
|
||||
<app-spinner *ngIf="model.pending"></app-spinner>
|
||||
<input [(ngModel)]="name" #model="ngModel" appSomeAsyncValidator>
|
||||
<app-spinner *ngIf="model.pending"></app-spinner>
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ The view-to-model diagram shows how data flows when an input field's value is ch
|
||||
```mermaid
|
||||
flowchart TB
|
||||
U{User}
|
||||
I("<input>")
|
||||
I("<input>")
|
||||
CVA(ControlValueAccessor)
|
||||
FC(FormControl)
|
||||
O(Observers)
|
||||
@@ -130,14 +130,14 @@ The model-to-view diagram shows how a programmatic change to the model is propag
|
||||
```mermaid
|
||||
flowchart TB
|
||||
U{User}
|
||||
I(<input>)
|
||||
I(<input>)
|
||||
CVA(ControlValueAccessor)
|
||||
FC(FormControl)
|
||||
O(Observers)
|
||||
U-->|"Calls setValue() on the FormControl"|FC
|
||||
FC-->|Notifies the ControlValueAccessor|CVA
|
||||
FC-.->|Fires a 'valueChanges' event to observers|O
|
||||
CVA-->|"Updates the value of the <input>"|I
|
||||
CVA-->|"Updates the value of the <input>"|I
|
||||
```
|
||||
|
||||
### Data flow in template-driven forms
|
||||
@@ -157,7 +157,7 @@ The view-to-model diagram shows how data flows when an input field's value is ch
|
||||
```mermaid
|
||||
flowchart TB
|
||||
U{User}
|
||||
I(<input>)
|
||||
I(<input>)
|
||||
CVA(ControlValueAccessor)
|
||||
FC(FormControl)
|
||||
M(NgModel)
|
||||
@@ -207,7 +207,7 @@ flowchart TB
|
||||
FC2(FormControl)
|
||||
O(Observers)
|
||||
CVA(ControlValueAccessor)
|
||||
I("<input>")
|
||||
I("<input>")
|
||||
FC2-.->|Fires a 'valueChanges' event to observers|O
|
||||
O-->|ControlValueAccessor receives valueChanges event|CVA
|
||||
CVA-->|Sets the value in the control|I
|
||||
|
||||
@@ -10,7 +10,7 @@ Angular supports two design approaches for interactive forms. Template-driven fo
|
||||
Template-driven forms are a great choice for small or simple forms, while reactive forms are more scalable and suitable for complex forms. For a comparison of the two approaches, see [Choosing an approach](guide/forms#choosing-an-approach)
|
||||
</docs-callout>
|
||||
|
||||
You can build almost any kind of form with an Angular template —login forms, contact forms, and pretty much any business form.
|
||||
You can build almost any kind of form with an Angular template —login forms, contact forms, and pretty much any business form.
|
||||
You can lay out the controls creatively and bind them to the data in your object model.
|
||||
You can specify validation rules and display validation errors, conditionally allow input from specific controls, trigger built-in visual feedback, and much more.
|
||||
|
||||
@@ -339,11 +339,11 @@ You will bind the form property that indicates its overall validity to the **Sub
|
||||
</docs-step>
|
||||
|
||||
<docs-step title="Run the application">
|
||||
Notice that the button is enabled —although it doesn't do anything useful yet.
|
||||
Notice that the button is enabled —although it doesn't do anything useful yet.
|
||||
</docs-step>
|
||||
|
||||
<docs-step title="Delete the Name value">
|
||||
This violates the "required" rule, so it displays the error message —and notice that it also disables the **Submit** button.
|
||||
This violates the "required" rule, so it displays the error message —and notice that it also disables the **Submit** button.
|
||||
|
||||
You didn't have to explicitly wire the button's enabled state to the form's validity.
|
||||
The `FormsModule` did this automatically when you defined a template reference variable on the enhanced form element, then referred to that variable in the button control.
|
||||
|
||||
@@ -83,11 +83,11 @@ HELPFUL: Prefer using [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/C
|
||||
|
||||
### `withXsrfConfiguration(...)`
|
||||
|
||||
Including this option allows for customization of `HttpClient`'s built-in XSRF security functionality. See the [security guide](best-practices/security) for more information.
|
||||
Including this option allows for customization of `HttpClient`'s built-in XSRF security functionality. See the [security guide](guide/http/security) for more information.
|
||||
|
||||
### `withNoXsrfProtection()`
|
||||
|
||||
Including this option disables `HttpClient`'s built-in XSRF security functionality. See the [security guide](best-practices/security) for more information.
|
||||
Including this option disables `HttpClient`'s built-in XSRF security functionality. See the [security guide](guide/http/security) for more information.
|
||||
|
||||
## `HttpClientModule`-based configuration
|
||||
|
||||
@@ -95,12 +95,12 @@ Some applications may configure `HttpClient` using the older API based on NgModu
|
||||
|
||||
This table lists the NgModules available from `@angular/common/http` and how they relate to the provider configuration functions above.
|
||||
|
||||
| **NgModule** | `provideHttpClient()` equivalent |
|
||||
| --------------------------------------- | --------------------------------------------- |
|
||||
| `HttpClientModule` | `provideHttpClient(withInterceptorsFromDi())` |
|
||||
| `HttpClientJsonpModule` | `withJsonpSupport()` |
|
||||
| `HttpClientXsrfModule.withOptions(...)` | `withXsrfConfiguration(...)` |
|
||||
| `HttpClientXsrfModule.disable()` | `withNoXsrfProtection()` |
|
||||
| **NgModule** | `provideHttpClient()` equivalent |
|
||||
| - | - |
|
||||
| `HttpClientModule` | `provideHttpClient(withInterceptorsFromDi())` |
|
||||
| `HttpClientJsonpModule` | `withJsonpSupport()` |
|
||||
| `HttpClientXsrfModule.withOptions(...)` | `withXsrfConfiguration(...)` |
|
||||
| `HttpClientXsrfModule.disable()` | `withNoXsrfProtection()` |
|
||||
|
||||
<docs-callout important title="Use caution when using HttpClientModule in multiple injectors">
|
||||
When `HttpClientModule` is present in multiple injectors, the behavior of interceptors is poorly defined and depends on the exact options and provider/import ordering.
|
||||
|
||||
@@ -18,7 +18,7 @@ To display the current date in the format for the current locale, use the follow
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
{{ today | date }}
|
||||
{{ today | date }}
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -32,7 +32,7 @@ To force the currency to use American English \(`en-US`\), use the following for
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
{{ amount | currency : 'en-US' }}
|
||||
{{ amount | currency : 'en-US' }}
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ The following example defines the `introductionHeader` custom ID for a variable.
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
variableText1 = $localize `:@@introductionHeader:Hello i18n!`;
|
||||
variableText1 = $localize `:@@introductionHeader:Hello i18n!`;
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -58,7 +58,7 @@ The following example defines the `introductionHeader` custom ID and description
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
variableText2 = $localize `:An introduction header for this sample@@introductionHeader:Hello i18n!`;
|
||||
variableText2 = $localize `:An introduction header for this sample@@introductionHeader:Hello i18n!`;
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -72,7 +72,7 @@ The following example defines the `introductionHeader` custom ID for a variable.
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
variableText3 = $localize `:site header|An introduction header for this sample@@introductionHeader:Hello i18n!`;
|
||||
variableText3 = $localize `:site header|An introduction header for this sample@@introductionHeader:Hello i18n!`;
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ To prepare your project for translation, complete the following actions.
|
||||
In a component template, the i18n metadata is the value of the `i18n` attribute.
|
||||
|
||||
<docs-code language="html">
|
||||
<element i18n="{i18n_metadata}">{string_to_translate}</element>
|
||||
<element i18n="{i18n_metadata}">{string_to_translate}</element>
|
||||
</docs-code>
|
||||
|
||||
Use the `i18n` attribute to mark a static text message in your component templates for translation.
|
||||
@@ -44,7 +44,7 @@ The following example shows the `<ng-container>` element transformed into a non-
|
||||
In a component template, the i18n metadata is the value of the `i18n-{attribute_name}` attribute.
|
||||
|
||||
<docs-code language="html">
|
||||
<element i18n-{attribute_name}="{i18n_metadata}" {attribute_name}="{attribute_value}" />
|
||||
<element i18n-{attribute_name}="{i18n_metadata}" {attribute_name}="{attribute_value}" />
|
||||
</docs-code>
|
||||
|
||||
The attributes of HTML elements include text that should be translated along with the rest of the displayed text in the component template.
|
||||
@@ -55,7 +55,7 @@ Use the following syntax to assign a meaning, description, and custom ID.
|
||||
<!--todo: replace with docs-code -->
|
||||
|
||||
<docs-code language="html">
|
||||
i18n-{attribute_name}="{meaning}|{description}@@{id}"
|
||||
i18n-{attribute_name}="{meaning}|{description}@@{id}"
|
||||
</docs-code>
|
||||
|
||||
### `i18n-title` example
|
||||
@@ -82,7 +82,7 @@ Use the [`$localize`][ApiLocalizeInitLocalize] tagged message string to mark a s
|
||||
<!--todo: replace with docs-code -->
|
||||
|
||||
<docs-code language="typescript">
|
||||
$localize `string_to_translate`;
|
||||
$localize `string_to_translate`;
|
||||
</docs-code>
|
||||
|
||||
The i18n metadata is surrounded by colon \(`:`\) characters and prepends the translation source text.
|
||||
@@ -90,7 +90,7 @@ The i18n metadata is surrounded by colon \(`:`\) characters and prepends the tra
|
||||
<!--todo: replace with docs-code -->
|
||||
|
||||
<docs-code language="typescript">
|
||||
$localize `:{i18n_metadata}:string_to_translate`
|
||||
$localize `:{i18n_metadata}:string_to_translate`
|
||||
</docs-code>
|
||||
|
||||
### Include interpolated text
|
||||
@@ -100,13 +100,13 @@ Include [interpolations](guide/templates/interpolation) in a [`$localize`][ApiLo
|
||||
<!--todo: replace with docs-code -->
|
||||
|
||||
<docs-code language="typescript">
|
||||
$localize `string_to_translate ${variable_name}`;
|
||||
$localize `string_to_translate ${variable_name}`;
|
||||
</docs-code>
|
||||
|
||||
### Name the interpolation placeholder
|
||||
|
||||
<docs-code language="typescript">
|
||||
$localize `string_to_translate ${variable_name}:placeholder_name:`;
|
||||
$localize `string_to_translate ${variable_name}:placeholder_name:`;
|
||||
</docs-code>
|
||||
|
||||
## i18n metadata for translation
|
||||
@@ -114,7 +114,7 @@ $localize `string_to_translate ${variable_name}:placeholder_name:`;
|
||||
<!--todo: replace with docs-code -->
|
||||
|
||||
<docs-code language="html">
|
||||
{meaning}|{description}@@{custom_id}
|
||||
{meaning}|{description}@@{custom_id}
|
||||
</docs-code>
|
||||
|
||||
The following parameters provide context and additional information to reduce confusion for your translator.
|
||||
@@ -143,7 +143,7 @@ The following example shows the value of the [`$localize`][ApiLocalizeInitLocali
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
$localize `:An introduction header for this sample:Hello i18n!`;
|
||||
$localize `:An introduction header for this sample:Hello i18n!`;
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -166,7 +166,7 @@ The following code example shows the value of the [`$localize`][ApiLocalizeInitL
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
$localize `:site header|An introduction header for this sample:Hello i18n!`;
|
||||
$localize `:site header|An introduction header for this sample:Hello i18n!`;
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ To create a translation file for a locale or language, complete the following ac
|
||||
|
||||
<docs-code language="file">
|
||||
|
||||
messages.xlf --> messages.{locale}.xlf
|
||||
messages.xlf --> messages.{locale}.xlf
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -132,20 +132,20 @@ The following actions describe the translation process for French.
|
||||
1. Open `messages.fr.xlf` and find the first `<trans-unit>` element.
|
||||
This is a *translation unit*, also known as a *text node*, that represents the translation of the `<h1>` greeting tag that was previously marked with the `i18n` attribute.
|
||||
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translated-hello-before"/>
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translated-hello-before"/>
|
||||
|
||||
The `id="introductionHeader"` is a [custom ID][GuideI18nOptionalManageMarkedText], but without the `@@` prefix required in the source HTML.
|
||||
|
||||
1. Duplicate the `<source>... </source>` element in the text node, rename it to `target`, and then replace the content with the French text.
|
||||
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>, after translation)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translated-hello"/>
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>, after translation)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translated-hello"/>
|
||||
|
||||
In a more complex translation, the information and context in the [description and meaning elements][GuideI18nCommonPrepareAddHelpfulDescriptionsAndMeanings] help you choose the right words for translation.
|
||||
|
||||
1. Translate the other text nodes.
|
||||
The following example displays the way to translate.
|
||||
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translated-other-nodes"/>
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translated-other-nodes"/>
|
||||
|
||||
IMPORTANT: Don't change the IDs for translation units.
|
||||
Each `id` attribute is generated by Angular and depends on the content of the component text and the assigned meaning.
|
||||
@@ -169,7 +169,7 @@ To translate a `plural`, translate the ICU format match values.
|
||||
|
||||
The following example displays the way to translate.
|
||||
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translated-plural"/>
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translated-plural"/>
|
||||
|
||||
## Translate alternate expressions
|
||||
|
||||
@@ -184,18 +184,18 @@ The following example displays a `select` ICU expression in the component templa
|
||||
In this example, Angular extracts the expression into two translation units.
|
||||
The first contains the text outside of the `select` clause, and uses a placeholder for `select` \(`<x id="ICU">`\):
|
||||
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translate-select-1"/>
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translate-select-1"/>
|
||||
|
||||
IMPORTANT: When you translate the text, move the placeholder if necessary, but don't remove it.
|
||||
If you remove the placeholder, the ICU expression is removed from your translated application.
|
||||
|
||||
The following example displays the second translation unit that contains the `select` clause.
|
||||
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translate-select-2"/>
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translate-select-2"/>
|
||||
|
||||
The following example displays both translation units after translation is complete.
|
||||
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translated-select"/>
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translated-select"/>
|
||||
|
||||
## Translate nested expressions
|
||||
|
||||
@@ -206,15 +206,15 @@ Angular extracts the expression into two translation units.
|
||||
|
||||
The following example displays the first translation unit that contains the text outside of the nested expression.
|
||||
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translate-nested-1"/>
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translate-nested-1"/>
|
||||
|
||||
The following example displays the second translation unit that contains the complete nested expression.
|
||||
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translate-nested-2"/>
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translate-nested-2"/>
|
||||
|
||||
The following example displays both translation units after translating.
|
||||
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translate-nested"/>
|
||||
<docs-code header="src/locale/messages.fr.xlf (<trans-unit>)" path="adev/src/content/examples/i18n/doc-files/messages.fr.xlf.html" visibleRegion="translate-nested"/>
|
||||
|
||||
## What's next
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ To activate the `NgOptimizedImage` directive, replace your image's `src` attribu
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
<img ngSrc="cat.jpg">
|
||||
<img ngSrc="cat.jpg">
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -63,7 +63,7 @@ Always mark the [LCP image](https://web.dev/lcp/#what-elements-are-considered) o
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
<img ngSrc="cat.jpg" width="400" height="200" priority>
|
||||
<img ngSrc="cat.jpg" width="400" height="200" priority>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -80,7 +80,7 @@ In order to prevent [image-related layout shifts](https://web.dev/css-web-vitals
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
<img ngSrc="cat.jpg" width="400" height="200">
|
||||
<img ngSrc="cat.jpg" width="400" height="200">
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -100,7 +100,7 @@ When you add the `fill` attribute to your image, you do not need and should not
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
<img ngSrc="cat.jpg" fill>
|
||||
<img ngSrc="cat.jpg" fill>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -120,7 +120,7 @@ NgOptimizedImage can display an automatic low-resolution placeholder for your im
|
||||
|
||||
<code-example format="typescript" language="typescript">
|
||||
|
||||
<img ngSrc="cat.jpg" width="400" height="200" placeholder>
|
||||
<img ngSrc="cat.jpg" width="400" height="200" placeholder>
|
||||
|
||||
</code-example>
|
||||
|
||||
@@ -147,7 +147,7 @@ You can also specify a placeholder using a base64 [data URL](https://developer.m
|
||||
|
||||
<code-example format="typescript" language="typescript">
|
||||
|
||||
<img ngSrc="cat.jpg" width="400" height="200" placeholder="data:image/png;base64,iVBORw0K...">
|
||||
<img ngSrc="cat.jpg" width="400" height="200" placeholder="data:image/png;base64,iVBORw0K...">
|
||||
|
||||
</code-example>
|
||||
|
||||
@@ -159,7 +159,7 @@ By default, NgOptimizedImage applies a CSS blur effect to image placeholders. To
|
||||
|
||||
<code-example format="typescript" language="typescript">
|
||||
|
||||
<img ngSrc="cat.jpg" width="400" height="200" placeholder [placeholderConfig]="{blur: false}">
|
||||
<img ngSrc="cat.jpg" width="400" height="200" placeholder [placeholderConfig]="{blur: false}">
|
||||
|
||||
</code-example>
|
||||
|
||||
@@ -181,7 +181,7 @@ You can add a [`preconnect` resource hint](https://web.dev/preconnect-and-dns-pr
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<link rel="preconnect" href="https://my.cdn.origin" />
|
||||
<link rel="preconnect" href="https://my.cdn.origin" />
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -236,7 +236,7 @@ If you would like to manually define a `srcset` attribute, you can provide your
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<img ngSrc="hero.jpg" ngSrcset="100w, 200w, 300w">
|
||||
<img ngSrc="hero.jpg" ngSrcset="100w, 200w, 300w">
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -244,7 +244,7 @@ If the `ngSrcset` attribute is present, `NgOptimizedImage` generates and sets th
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<img ngSrc="hero.jpg" ngSrcset="100w, 200w, 300w" sizes="50vw">
|
||||
<img ngSrc="hero.jpg" ngSrcset="100w, 200w, 300w" sizes="50vw">
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -254,7 +254,7 @@ To disable srcset generation for a single image, you can add the `disableOptimiz
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<img ngSrc="about.jpg" disableOptimizedSrcset>
|
||||
<img ngSrc="about.jpg" disableOptimizedSrcset>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -264,7 +264,7 @@ By default, `NgOptimizedImage` sets `loading=lazy` for all images that are not m
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<img ngSrc="cat.jpg" width="400" height="200" loading="eager">
|
||||
<img ngSrc="cat.jpg" width="400" height="200" loading="eager">
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -274,7 +274,7 @@ You may want to have images displayed at varying widths on differently-sized scr
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<img ngSrc="cat.jpg" width="400" height="200" sizes="(max-width: 768px) 100vw, 50vw">
|
||||
<img ngSrc="cat.jpg" width="400" height="200" sizes="(max-width: 768px) 100vw, 50vw">
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -371,7 +371,7 @@ Note that in the above example, we've invented the 'roundedCorners' property nam
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<img ngSrc="profile.jpg" width="300" height="300" [loaderParams]="{roundedCorners: true}">
|
||||
<img ngSrc="profile.jpg" width="300" height="300" [loaderParams]="{roundedCorners: true}">
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -31,10 +31,10 @@ The following table summarizes the `@NgModule` metadata properties.
|
||||
|
||||
| Property | Details |
|
||||
|:--- |:--- |
|
||||
| `declarations` | A list of [declarable](/guide/ngmodules/faq#what-is-a-declarable?) classes (*components*, *directives*, and *pipes*) that *belong to this module*. <ol> <li> When compiling a template, you need to determine a set of selectors which should be used for triggering their corresponding directives. </li> <li> The template is compiled within the context of an NgModule —the NgModule within which the template's component is declared— which determines the set of selectors using the following rules: <ul> <li> All selectors of directives listed in `declarations`. </li> <li> All selectors of directives exported from imported NgModules. </li> </ul> </li> </ol> Components, directives, and pipes must belong to *exactly* one module. The compiler emits an error if you try to declare the same class in more than one module. Be careful not to re-declare a class that is imported directly or indirectly from another module. |
|
||||
| `declarations` | A list of [declarable](/guide/ngmodules/faq#what-is-a-declarable?) classes (*components*, *directives*, and *pipes*) that *belong to this module*. <ol> <li> When compiling a template, you need to determine a set of selectors which should be used for triggering their corresponding directives. </li> <li> The template is compiled within the context of an NgModule —the NgModule within which the template's component is declared— which determines the set of selectors using the following rules: <ul> <li> All selectors of directives listed in `declarations`. </li> <li> All selectors of directives exported from imported NgModules. </li> </ul> </li> </ol> Components, directives, and pipes must belong to *exactly* one module. The compiler emits an error if you try to declare the same class in more than one module. Be careful not to re-declare a class that is imported directly or indirectly from another module. |
|
||||
| `providers` | A list of dependency-injection providers. <br /> Angular registers these providers with the NgModule's injector. If it is the NgModule used for bootstrapping then it is the root injector. <br /> These services become available for injection into any component, directive, pipe or service which is a child of this injector. <br /> A lazy-loaded module has its own injector which is typically a child of the application root injector. <br /> Lazy-loaded services are scoped to the lazy module's injector. If a lazy-loaded module also provides the `UserService`, any component created within that module's context (such as by router navigation) gets the local instance of the service, not the instance in the root application injector. <br /> Components in external modules continue to receive the instance provided by their injectors. <br /> For more information on injector hierarchy and scoping, see [Providers](/guide/ngmodules/providers) and the [DI Guide](/guide/di). |
|
||||
| `imports` | A list of modules which should be folded into this module. Folded means it is as if all the imported NgModule's exported properties were declared here. <br /> Specifically, it is as if the list of modules whose exported components, directives, or pipes are referenced by the component templates were declared in this module. <br /> A component template can [reference](/guide/ngmodules/faq#how-does-angular-find-components,-directives,-and-pipes-in-a-template?-what-is-a-template-reference?) another component, directive, or pipe when the reference is declared in this module or if the imported module has exported it. For example, a component can use the `NgIf` and `NgFor` directives only if the module has imported the Angular `CommonModule` (perhaps indirectly by importing `BrowserModule`). <br /> You can import many standard directives from the `CommonModule` but some familiar directives belong to other modules. For example, you can use `[(ngModel)]` only after importing the Angular `FormsModule`. |
|
||||
| `exports` | A list of declarations —*component*, *directive*, and *pipe* classes— that an importing module can use. <br /> Exported declarations are the module's *public API*. A component in another module can use *this* module's `UserComponent` if it imports this module and this module exports `UserComponent`. <br /> Declarations are private by default. If this module does *not* export `UserComponent`, then only the components within *this* module can use `UserComponent`. <br /> Importing a module does *not* automatically re-export the imported module's imports. Module 'B' can't use `ngIf` just because it imported module 'A' which imported `CommonModule`. Module 'B' must import `CommonModule` itself. <br /> A module can list another module among its `exports`, in which case all of that module's public components, directives, and pipes are exported. <br /> [Re-export](/guide/ngmodules/faq#what-should-i-export?) makes module transitivity explicit. If Module 'A' re-exports `CommonModule` and Module 'B' imports Module 'A', Module 'B' components can use `ngIf` even though 'B' itself didn't import `CommonModule`. |
|
||||
| `exports` | A list of declarations —*component*, *directive*, and *pipe* classes— that an importing module can use. <br /> Exported declarations are the module's *public API*. A component in another module can use *this* module's `UserComponent` if it imports this module and this module exports `UserComponent`. <br /> Declarations are private by default. If this module does *not* export `UserComponent`, then only the components within *this* module can use `UserComponent`. <br /> Importing a module does *not* automatically re-export the imported module's imports. Module 'B' can't use `ngIf` just because it imported module 'A' which imported `CommonModule`. Module 'B' must import `CommonModule` itself. <br /> A module can list another module among its `exports`, in which case all of that module's public components, directives, and pipes are exported. <br /> [Re-export](/guide/ngmodules/faq#what-should-i-export?) makes module transitivity explicit. If Module 'A' re-exports `CommonModule` and Module 'B' imports Module 'A', Module 'B' components can use `ngIf` even though 'B' itself didn't import `CommonModule`. |
|
||||
| `bootstrap` | A list of components that are automatically bootstrapped. <br /> Usually there's only one component in this list, the *root component* of the application. <br /> Angular can launch with multiple bootstrap components, each with its own location in the host web page. |
|
||||
|
||||
## More on NgModules
|
||||
|
||||
@@ -6,14 +6,14 @@ This page answers the questions many developers ask about NgModule design and im
|
||||
|
||||
## What classes should I add to the `declarations` array?
|
||||
|
||||
Add [declarable](/guide/ngmodules/bootstrapping#the-declarations-array) classes —components, directives, and pipes— to a `declarations` list.
|
||||
Add [declarable](/guide/ngmodules/bootstrapping#the-declarations-array) classes —components, directives, and pipes— to a `declarations` list.
|
||||
|
||||
Declare these classes in *exactly one* module of the application.
|
||||
Declare them in a module if they belong to that particular module.
|
||||
|
||||
## What is a `declarable`?
|
||||
|
||||
Declarables are the class types —components, directives, and pipes— that you can add to a module's `declarations` list.
|
||||
Declarables are the class types —components, directives, and pipes— that you can add to a module's `declarations` list.
|
||||
They're the only classes that you can add to `declarations`.
|
||||
|
||||
## What classes should I *not* add to `declarations`?
|
||||
@@ -97,7 +97,7 @@ Export [declarable](/guide/ngmodules/bootstrapping#the-declarations-array) class
|
||||
These are your *public* classes.
|
||||
If you don't export a declarable class, it stays *private*, visible only to other components declared in this NgModule.
|
||||
|
||||
You *can* export any declarable class —components, directives, and pipes— whether
|
||||
You *can* export any declarable class —components, directives, and pipes— whether
|
||||
it's declared in this NgModule or in an imported NgModule.
|
||||
|
||||
You *can* re-export entire imported NgModules, which effectively re-export all of their exported classes.
|
||||
@@ -389,7 +389,7 @@ In an Angular app, NgModules and JavaScript modules work together.
|
||||
In modern JavaScript, every file is a module (see the [Modules](https://exploringjs.com/es6/ch_modules.html) page of the Exploring ES6 website).
|
||||
Within each file you write an `export` statement to make parts of the module public.
|
||||
|
||||
An Angular NgModule is a class with the `@NgModule` decorator —JavaScript modules don't have to have the `@NgModule` decorator.
|
||||
An Angular NgModule is a class with the `@NgModule` decorator —JavaScript modules don't have to have the `@NgModule` decorator.
|
||||
Angular's `NgModule` has `imports` and `exports` and they serve a similar purpose.
|
||||
|
||||
You *import* other NgModules so you can use their exported classes in component templates.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Lazy-loading feature modules
|
||||
|
||||
By default, NgModules are eagerly loaded. This means that as soon as the application loads, so do all the NgModules, whether they are immediately necessary or not.
|
||||
For large applications with lots of routes, consider lazy loading —a design pattern that loads NgModules as needed.
|
||||
For large applications with lots of routes, consider lazy loading —a design pattern that loads NgModules as needed.
|
||||
Lazy loading helps keep initial bundle sizes smaller, which in turn helps decrease load times.
|
||||
|
||||
<!-- For the final sample application with two lazy-loaded modules that this page describes: -->
|
||||
@@ -363,7 +363,7 @@ In the newly created service, implement the `Resolve` interface provided by the
|
||||
|
||||
import { Resolve } from '@angular/router';
|
||||
|
||||
…
|
||||
…
|
||||
|
||||
/*An interface that represents your data model*/
|
||||
export interface Crisis {
|
||||
@@ -371,8 +371,8 @@ export interface Crisis {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class CrisisDetailResolverService implements Resolve<Crisis> {
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Crisis> {
|
||||
export class CrisisDetailResolverService implements Resolve<Crisis> {
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Crisis> {
|
||||
// your logic goes here
|
||||
}
|
||||
}
|
||||
@@ -405,7 +405,7 @@ In the component's constructor, inject an instance of the `ActivatedRoute` class
|
||||
<docs-code header="Component's constructor (excerpt)">
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({ … })
|
||||
@Component({ … })
|
||||
class YourComponent {
|
||||
constructor(private route: ActivatedRoute) {}
|
||||
}
|
||||
@@ -417,7 +417,7 @@ Use the injected instance of the `ActivatedRoute` class to access `data` associa
|
||||
highlight="[1,5,8]">
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({ … })
|
||||
@Component({ … })
|
||||
class YourComponent {
|
||||
constructor(private route: ActivatedRoute) {}
|
||||
|
||||
@@ -425,7 +425,7 @@ class YourComponent {
|
||||
this.route.data
|
||||
.subscribe(data => {
|
||||
const crisis: Crisis = data.crisis;
|
||||
// …
|
||||
// …
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Guidelines for creating NgModules
|
||||
|
||||
This topic provides a conceptual overview of the different categories of NgModules you can create in order to organize your code in a modular structure.
|
||||
These categories are not cast in stone —they are suggestions.
|
||||
These categories are not cast in stone —they are suggestions.
|
||||
You may want to create NgModules for other purposes, or combine the characteristics of some of these categories.
|
||||
|
||||
NgModules are a great way to organize an application and keep code related to a specific functionality or feature separate from other code.
|
||||
|
||||
@@ -14,7 +14,7 @@ For the module specification, see the [6th Edition of the ECMAScript standard](h
|
||||
To make the code in a JavaScript module available to other modules, use an `export` statement at the end of the relevant code in the module, such as the following:
|
||||
|
||||
<docs-code language="typescript">
|
||||
export class AppComponent { … }
|
||||
export class AppComponent { … }
|
||||
</docs-code>
|
||||
|
||||
When you need that module's code in another module, use an `import` statement as follows:
|
||||
|
||||
@@ -97,7 +97,7 @@ Make a pipe impure by setting its `pure` flag to `false`:
|
||||
visibleRegion="pipe-decorator" highlight="[19]"/>
|
||||
|
||||
The following code shows the complete implementation of `FlyingHeroesImpurePipe`, which extends `FlyingHeroesPipe` to inherit its characteristics.
|
||||
The example shows that you don't have to change anything else—the only difference is setting the `pure` flag as `false` in the pipe metadata.
|
||||
The example shows that you don't have to change anything else—the only difference is setting the `pure` flag as `false` in the pipe metadata.
|
||||
|
||||
<docs-code-multifile>
|
||||
<docs-code header="src/app/flying-heroes.pipe.ts (FlyingHeroesImpurePipe)" path="adev/src/content/examples/pipes/src/app/flying-heroes.pipe.ts" visibleRegion="impure"/>
|
||||
|
||||
@@ -380,7 +380,7 @@ The router uses an `id` to show the correct hero's details.
|
||||
First, import the following members in the component you want to navigate from.
|
||||
|
||||
```ts
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
```
|
||||
|
||||
@@ -59,7 +59,7 @@ The data property is accessible within each activated route.
|
||||
Use it to store items such as page titles, breadcrumb text, and other read-only, static data.
|
||||
Use the resolve guard to retrieve dynamic data.
|
||||
|
||||
The empty path in the fourth route represents the default path for the application —the place to go when the path in the URL is empty, as it typically is at the start.
|
||||
The empty path in the fourth route represents the default path for the application —the place to go when the path in the URL is empty, as it typically is at the start.
|
||||
This default route redirects to the route for the `/heroes` URL and, therefore, displays the `HeroesListComponent`.
|
||||
|
||||
If you need to see what events are happening during the navigation lifecycle, there is the `withDebugTracing` feature.
|
||||
@@ -74,8 +74,8 @@ It acts as a placeholder that marks the spot in the template where the router sh
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
<!-- Routed components go here -->
|
||||
<router-outlet></router-outlet>
|
||||
<!-- Routed components go here -->
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ This is one of the most common attacks on the web.
|
||||
|
||||
To block XSS attacks, you must prevent malicious code from entering the Document Object Model (DOM).
|
||||
For example, if attackers can trick you into inserting a `<script>` tag in the DOM, they can run arbitrary code on your website.
|
||||
The attack isn't limited to `<script>` tags —many elements and properties in the DOM allow code execution, for example, `<img alt="" onerror="...">` and `<a href="javascript:...">`.
|
||||
The attack isn't limited to `<script>` tags —many elements and properties in the DOM allow code execution, for example, `<img alt="" onerror="...">` and `<a href="javascript:...">`.
|
||||
If attacker-controlled data enters the DOM, expect security vulnerabilities.
|
||||
|
||||
### Angular's cross-site scripting security model
|
||||
@@ -72,7 +72,7 @@ The following template binds the value of `htmlSnippet`. Once by interpolating i
|
||||
|
||||
<docs-code header="src/app/inner-html-binding.component.html" path="adev/src/content/examples/security/src/app/inner-html-binding.component.html"/>
|
||||
|
||||
Interpolated content is always escaped —the HTML isn't interpreted and the browser displays angle brackets in the element's text content.
|
||||
Interpolated content is always escaped —the HTML isn't interpreted and the browser displays angle brackets in the element's text content.
|
||||
|
||||
For the HTML to be interpreted, bind it to an HTML property such as `innerHTML`.
|
||||
Be aware that binding a value that an attacker might control into `innerHTML` normally causes an XSS vulnerability.
|
||||
@@ -93,7 +93,7 @@ Avoid directly interacting with the DOM and instead use Angular templates where
|
||||
|
||||
For cases where this is unavoidable, use the built-in Angular sanitization functions.
|
||||
Sanitize untrusted values with the [DomSanitizer.sanitize](api/platform-browser/DomSanitizer#sanitize) method and the appropriate `SecurityContext`.
|
||||
That function also accepts values that were marked as trusted using the `bypassSecurityTrust` … functions, and does not sanitize them, as [described below](#trusting-safe-values).
|
||||
That function also accepts values that were marked as trusted using the `bypassSecurityTrust` … functions, and does not sanitize them, as [described below](#trusting-safe-values).
|
||||
|
||||
### Trusting safe values
|
||||
|
||||
@@ -155,7 +155,7 @@ You can set the nonce for Angular in one of two ways:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
import {bootstrapApplication, CSP_NONCE} from '@angular/core';
|
||||
import {bootstrapApplication, CSP_NONCE} from '@angular/core';
|
||||
import {AppComponent} from './app/app.component';
|
||||
|
||||
bootstrapApplication(AppComponent, {
|
||||
@@ -301,56 +301,8 @@ Only code from the website on which cookies are set can read the cookies from th
|
||||
That means only your application can read this cookie token and set the custom header.
|
||||
The malicious code on `evil.com` can't.
|
||||
|
||||
### `HttpClient` XSRF/CSRF security
|
||||
|
||||
`HttpClient` supports a [common mechanism](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Cookie-to-header_token) used to prevent XSRF attacks. When performing HTTP requests, an interceptor reads a token from a cookie, by default `XSRF-TOKEN`, and sets it as an HTTP header, `X-XSRF-TOKEN`. Because only code that runs on your domain could read the cookie, the backend can be certain that the HTTP request came from your client application and not an attacker.
|
||||
|
||||
By default, an interceptor sends this header on all mutating requests (such as `POST`) to relative URLs, but not on GET/HEAD requests or on requests with an absolute URL.
|
||||
|
||||
<docs-callout helpful title="Why not protect GET requests?">
|
||||
CSRF protection is only needed for requests that can change state on the backend. By their nature, CSRF attacks cross domain boundaries, and the web's [same-origin policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) will prevent an attacking page from retrieving the results of authenticated GET requests.
|
||||
</docs-callout>
|
||||
|
||||
To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called `XSRF-TOKEN` on either the page load or the first GET request. On subsequent requests the server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be sure that only code running on your domain could have sent the request. The token must be unique for each user and must be verifiable by the server; this prevents the client from making up its own tokens. Set the token to a digest of your site's authentication cookie with a salt for added security.
|
||||
|
||||
To prevent collisions in environments where multiple Angular apps share the same domain or subdomain, give each application a unique cookie name.
|
||||
|
||||
<docs-callout important title="HttpClient supports only the client half of the XSRF protection scheme">
|
||||
Your backend service must be configured to set the cookie for your page, and to verify that the header is present on all eligible requests. Failing to do so renders Angular's default protection ineffective.
|
||||
</docs-callout>
|
||||
|
||||
### Configure custom cookie/header names
|
||||
|
||||
If your backend service uses different names for the XSRF token cookie or header, use `withXsrfConfiguration` to override the defaults.
|
||||
|
||||
Add it to the `provideHttpClient` call as follows:
|
||||
|
||||
<docs-code language="ts">
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideHttpClient(
|
||||
withXsrfConfiguration({
|
||||
cookieName: 'CUSTOM_XSRF_TOKEN',
|
||||
headerName: 'X-Custom-Xsrf-Header',
|
||||
}),
|
||||
),
|
||||
]
|
||||
};
|
||||
</docs-code>
|
||||
|
||||
### Disabling XSRF protection
|
||||
|
||||
If the built-in XSRF protection mechanism doesn't work for your application, you can disable it using the `withNoXsrfProtection` feature:
|
||||
|
||||
<docs-code language="ts">
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideHttpClient(
|
||||
withNoXsrfProtection(),
|
||||
),
|
||||
]
|
||||
};
|
||||
</docs-code>
|
||||
Angular's `HttpClient` has built-in support for the client-side half of this technique.
|
||||
Read about it more in the [HttpClient guide](/guide/http/security#xsrf-csrf-protection).
|
||||
|
||||
For information about CSRF at the Open Web Application Security Project \(OWASP\), see [Cross-Site Request Forgery (CSRF)](https://owasp.org/www-community/attacks/csrf) and [Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html).
|
||||
The Stanford University paper [Robust Defenses for Cross-Site Request Forgery](https://seclab.stanford.edu/websec/csrf/csrf.pdf) is a rich source of detail.
|
||||
|
||||
@@ -28,10 +28,6 @@ Like the `async` pipe, `toSignal` subscribes to the Observable immediately, whic
|
||||
|
||||
IMPORTANT: `toSignal` creates a subscription. You should avoid calling it repeatedly for the same Observable, and instead reuse the signal it returns.
|
||||
|
||||
### Injection context
|
||||
|
||||
`toSignal` by default needs to run in an [injection context](guide/di/dependency-injection-context), such as during construction of a component or service. If an injection context is not available, you can manually specify the `Injector` to use instead.
|
||||
|
||||
### Initial values
|
||||
|
||||
Observables may not produce a value synchronously on subscription, but signals always require a current value. There are several ways to deal with this "initial" value of `toSignal` signals.
|
||||
|
||||
@@ -10,7 +10,7 @@ Then, you set the attribute value with an expression that resolves to a string.
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<p [attr.attribute-you-are-targeting]="expression"></p>
|
||||
<p [attr.attribute-you-are-targeting]="expression"></p>
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Other notable differences from JavaScript syntax include:
|
||||
|
||||
## Expression context
|
||||
|
||||
Interpolated expressions have a context—a particular part of the application to which the expression belongs. Typically, this context is the component instance.
|
||||
Interpolated expressions have a context—a particular part of the application to which the expression belongs. Typically, this context is the component instance.
|
||||
|
||||
In the following snippet, the expression `recommended` and the expression `itemImageUrl2` refer to properties of the `AppComponent`.
|
||||
|
||||
@@ -50,7 +50,7 @@ HELPFUL: Template expressions cannot refer to anything in the global namespace,
|
||||
|
||||
### Preventing name collisions
|
||||
|
||||
The context against which an expression evaluates is the union of the template variables, the directive's context object—if it has one—and the component's members.
|
||||
The context against which an expression evaluates is the union of the template variables, the directive's context object—if it has one—and the component's members.
|
||||
If you reference a name that belongs to more than one of these namespaces, Angular applies the following precedence logic to determine the context:
|
||||
|
||||
1. The template variable name.
|
||||
|
||||
@@ -8,7 +8,7 @@ To create a single class binding, type the following:
|
||||
|
||||
`[class.sale]="onSale"`
|
||||
|
||||
Angular adds the class when the bound expression, `onSale` is truthy, and it removes the class when the expression is falsy—with the exception of `undefined`.
|
||||
Angular adds the class when the bound expression, `onSale` is truthy, and it removes the class when the expression is falsy—with the exception of `undefined`.
|
||||
|
||||
## Binding to multiple CSS classes
|
||||
|
||||
@@ -24,7 +24,7 @@ The expression can be one of:
|
||||
|
||||
With the object format, Angular adds a class only if its associated value is truthy.
|
||||
|
||||
IMPORTANT: With any object-like expression—such as `object`, `Array`, `Map`, or `Set` —the identity of the object must change for Angular to update the class list.
|
||||
IMPORTANT: With any object-like expression—such as `object`, `Array`, `Map`, or `Set` —the identity of the object must change for Angular to update the class list.
|
||||
Updating the property without changing object identity has no effect.
|
||||
|
||||
If there are multiple bindings to the same class name, Angular uses styling precedence to determine which binding to use.
|
||||
@@ -33,10 +33,10 @@ The following table summarizes class binding syntax.
|
||||
|
||||
| Binding Type | Syntax | Input Type | Example Input Values |
|
||||
|:--- |:--- |:--- |:--- |
|
||||
| Single class binding | `[class.sale]="onSale"` | <code>boolean | undefined | null</code> | `true`, `false` |
|
||||
| Single class binding | `[class.sale]="onSale"` | <code>boolean | undefined | null</code> | `true`, `false` |
|
||||
| Multi-class binding | `[class]="classExpression"` | `string` | `"my-class-1 my-class-2 my-class-3"` |
|
||||
| Multi-class binding | `[class]="classExpression"` | <code>Record<string, boolean | undefined | null></code> | `{foo: true, bar: false}` |
|
||||
| Multi-class binding | `[class]="classExpression"` | <code>Array<string></code> | `['foo', 'bar']` |
|
||||
| Multi-class binding | `[class]="classExpression"` | <code>Record<string, boolean | undefined | null></code> | `{foo: true, bar: false}` |
|
||||
| Multi-class binding | `[class]="classExpression"` | <code>Array<string></code> | `['foo', 'bar']` |
|
||||
|
||||
## Binding to a single style
|
||||
|
||||
@@ -48,15 +48,15 @@ Angular sets the property to the value of the bound expression, which is usually
|
||||
|
||||
1. To write a style in dash-case, type the following:
|
||||
|
||||
<docs-code language="html"><nav [style.background-color]="expression"></nav></docs-code>
|
||||
<docs-code language="html"><nav [style.background-color]="expression"></nav></docs-code>
|
||||
|
||||
2. To write a style in camelCase, type the following:
|
||||
|
||||
<docs-code language="html"><nav [style.backgroundColor]="expression"></nav></docs-code>
|
||||
<docs-code language="html"><nav [style.backgroundColor]="expression"></nav></docs-code>
|
||||
|
||||
## Binding to multiple styles
|
||||
|
||||
To toggle multiple styles, bind to the `[style]` attribute—for example, `[style]="styleExpression"`. The `styleExpression` can be one of:
|
||||
To toggle multiple styles, bind to the `[style]` attribute—for example, `[style]="styleExpression"`. The `styleExpression` can be one of:
|
||||
|
||||
* A string list of styles such as `"width: 100px; height: 100px; background-color: cornflowerblue;"`.
|
||||
* An object with style names as the keys and style values as the values, such as `{width: '100px', height: '100px', backgroundColor: 'cornflowerblue'}`.
|
||||
@@ -76,10 +76,10 @@ The following table summarizes style binding syntax.
|
||||
|
||||
| Binding Type | Syntax | Input Type | Example Input Values |
|
||||
|:--- |:--- |:--- |:--- |
|
||||
| Single style binding | `[style.width]="width"` | <code>string | undefined | null</code> | `"100px"` |
|
||||
| Single style binding with units | `[style.width.px]="width"` | <code>number | undefined | null</code> | `100` |
|
||||
| Single style binding | `[style.width]="width"` | <code>string | undefined | null</code> | `"100px"` |
|
||||
| Single style binding with units | `[style.width.px]="width"` | <code>number | undefined | null</code> | `100` |
|
||||
| Multi-style binding | `[style]="styleExpression"` | `string` | `"width: 100px; height: 100px"` |
|
||||
| Multi-style binding | `[style]="styleExpression"` | <code>Record<string, string | undefined | null></code> | `{width: '100px', height: '100px'}` |
|
||||
| Multi-style binding | `[style]="styleExpression"` | <code>Record<string, string | undefined | null></code> | `{width: '100px', height: '100px'}` |
|
||||
|
||||
## Styling precedence
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ This syntax consists of a target event name within parentheses to the left of an
|
||||
Create the following example; the target event name is `click` and the template statement is `onSave()`.
|
||||
|
||||
<docs-code language="html" header="Event binding syntax">
|
||||
<button (click)="onSave()">Save</button>
|
||||
<button (click)="onSave()">Save</button>
|
||||
</docs-code>
|
||||
|
||||
The event binding listens for the button's click events and calls the component's `onSave()` method whenever a click occurs.
|
||||
|
||||
@@ -30,7 +30,7 @@ The following JavaScript and template expression syntax is not allowed:
|
||||
|
||||
## Statement context
|
||||
|
||||
Statements have a context —a particular part of the application to which the statement belongs.
|
||||
Statements have a context —a particular part of the application to which the statement belongs.
|
||||
|
||||
Statements can refer only to what's in the statement context, which is typically the component instance.
|
||||
For example, `deleteHero()` of `(click)="deleteHero()"` is a method of the component in the following snippet.
|
||||
|
||||
@@ -33,7 +33,7 @@ To enable this, open the [Karma](https://karma-runner.github.io) test platform c
|
||||
|
||||
<docs-code language="javascript">
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/<project-name>'),
|
||||
dir: require('path').join(__dirname, './coverage/<project-name>'),
|
||||
subdir: '.',
|
||||
reporters: [
|
||||
{ type: 'html' },
|
||||
|
||||
@@ -272,7 +272,7 @@ HELPFUL: The `it()` function receives an argument of the following form.
|
||||
|
||||
<docs-code language="javascript">
|
||||
|
||||
fakeAsync(() => { /*test body*/ })
|
||||
fakeAsync(() => { /*test body*/ })
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -593,7 +593,7 @@ The following test verifies that the hero name is propagated to the template usi
|
||||
|
||||
Because the [template](#dashboard-hero-component) passes the hero name through the Angular `UpperCasePipe`, the test must match the element value with the upper-cased name.
|
||||
|
||||
HELPFUL: This small test demonstrates how Angular tests can verify a component's visual representation —something not possible with [component class tests](guide/testing/components-basics#component-class-testing)— at low cost and without resorting to much slower and more complicated end-to-end tests.
|
||||
HELPFUL: This small test demonstrates how Angular tests can verify a component's visual representation —something not possible with [component class tests](guide/testing/components-basics#component-class-testing)— at low cost and without resorting to much slower and more complicated end-to-end tests.
|
||||
|
||||
### Clicking
|
||||
|
||||
@@ -866,7 +866,7 @@ But there's plenty of template complexity even in this simple form.
|
||||
<docs-code
|
||||
path="adev/src/content/examples/testing/src/app/hero/hero-detail.component.html" header="app/hero/hero-detail.component.html"/>
|
||||
|
||||
Tests that exercise the component need …
|
||||
Tests that exercise the component need …
|
||||
|
||||
* To wait until a hero arrives before elements appear in the DOM
|
||||
* A reference to the title text
|
||||
@@ -1089,10 +1089,10 @@ The [override metadata object](guide/testing/utility-apis#metadata-override-obje
|
||||
|
||||
<docs-code language="javascript">
|
||||
|
||||
type MetadataOverride<T> = {
|
||||
add?: Partial<T>;
|
||||
remove?: Partial<T>;
|
||||
set?: Partial<T>;
|
||||
type MetadataOverride<T> = {
|
||||
add?: Partial<T>;
|
||||
remove?: Partial<T>;
|
||||
set?: Partial<T>;
|
||||
};
|
||||
|
||||
</docs-code>
|
||||
@@ -1108,7 +1108,7 @@ selector?: string;
|
||||
template?: string;
|
||||
templateUrl?: string;
|
||||
providers?: any[];
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ type TestModuleMetadata = {
|
||||
providers?: any[];
|
||||
declarations?: any[];
|
||||
imports?: any[];
|
||||
schemas?: Array<SchemaMetadata | any[]>;
|
||||
schemas?: Array<SchemaMetadata | any[]>;
|
||||
};
|
||||
|
||||
</docs-code>
|
||||
@@ -41,10 +41,10 @@ Each override method takes a `MetadataOverride<T>` where `T` is the kind of meta
|
||||
|
||||
<docs-code language="javascript">
|
||||
|
||||
type MetadataOverride<T> = {
|
||||
add?: Partial<T>;
|
||||
remove?: Partial<T>;
|
||||
set?: Partial<T>;
|
||||
type MetadataOverride<T> = {
|
||||
add?: Partial<T>;
|
||||
remove?: Partial<T>;
|
||||
set?: Partial<T>;
|
||||
};
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -36,10 +36,10 @@ The following properties are a set of options that customize the Angular CLI.
|
||||
|
||||
| Property | Details | Value type | Default value |
|
||||
|:--- |:--- |:--- |:--- |
|
||||
| `analytics` | Share anonymous usage data with the Angular Team. A boolean value indicates whether or not to share data, while a UUID string shares data using a pseudonymous identifier. | `boolean` | `string` | `false` |
|
||||
| `analytics` | Share anonymous usage data with the Angular Team. A boolean value indicates whether or not to share data, while a UUID string shares data using a pseudonymous identifier. | `boolean` | `string` | `false` |
|
||||
| `cache` | Control [persistent disk cache](cli/cache) used by [Angular CLI Builders](tools/cli/cli-builder). | [Cache options](#cache-options) | `{}` |
|
||||
| `schematicCollections`| List schematics collections to use in `ng generate`. | `string[]` | `[]` |
|
||||
| `packageManager` | The preferred package manager tool to use. | `npm` | `cnpm` | `pnpm` | `yarn` | `npm` |
|
||||
| `packageManager` | The preferred package manager tool to use. | `npm` | `cnpm` | `pnpm` | `yarn` | `npm` |
|
||||
| `warnings` | Control Angular CLI specific console warnings. | [Warnings options](#warnings-options) | `{}` |
|
||||
|
||||
### Cache options
|
||||
@@ -47,7 +47,7 @@ The following properties are a set of options that customize the Angular CLI.
|
||||
| Property | Details | Value type | Default value |
|
||||
|:--- |:--- |:--- |:--- |
|
||||
| `enabled` | Configure whether disk caching is enabled for builds. | `boolean` | `true` |
|
||||
| `environment` | Configure in which environment disk cache is enabled.<br><br>* `ci` enables caching only in continuous integration (CI) environments.<br>* `local` enables caching only *outside* of CI environments.<br>* `all` enables caching everywhere. | `local` | `ci` | `all` | `local` |
|
||||
| `environment` | Configure in which environment disk cache is enabled.<br><br>* `ci` enables caching only in continuous integration (CI) environments.<br>* `local` enables caching only *outside* of CI environments.<br>* `all` enables caching everywhere. | `local` | `ci` | `all` | `local` |
|
||||
| `path` | The directory used to stored cache results. | `string` | `.angular/cache` |
|
||||
|
||||
### Warnings options
|
||||
@@ -63,7 +63,7 @@ The following top-level configuration properties are available for each project,
|
||||
| Property | Details | Value type | Default value |
|
||||
|:--- |:--- |:--- |:--- |
|
||||
| `root` | The root directory for this project's files, relative to the workspace directory. Empty for the initial application, which resides at the top level of the workspace. | `string` | None (required) |
|
||||
| `projectType` | One of "application" or "library" An application can run independently in a browser, while a library cannot. | `application` | `library` | None (required) |
|
||||
| `projectType` | One of "application" or "library" An application can run independently in a browser, while a library cannot. | `application` | `library` | None (required) |
|
||||
| `sourceRoot` | The root directory for this project's source files. | `string` | `''` |
|
||||
| `prefix` | A string that Angular prepends to selectors when generating new components, directives, and pipes using `ng generate`. Can be customized to identify an application or feature area. | `string` | `'app'` |
|
||||
| `schematics` | A set of schematics that customize the `ng generate` sub-command option defaults for this project. See the [Generation schematics](#schematics) section. | See [schematics](#schematics) | `{}` |
|
||||
@@ -409,8 +409,8 @@ Several options can be used to fine-tune the optimization of an application.
|
||||
| Options | Details | Value type | Default value |
|
||||
|:--- |:--- |:--- |:--- |
|
||||
| `scripts` | Enables optimization of the scripts output. | `boolean` | `true` |
|
||||
| `styles` | Enables optimization of the styles output. | `boolean` | [Styles optimization options](#styles-optimization-options) | `true` |
|
||||
| `fonts` | Enables optimization for fonts. This requires internet access. | `boolean` | [Fonts optimization options](#fonts-optimization-options) | `true` |
|
||||
| `styles` | Enables optimization of the styles output. | `boolean` | [Styles optimization options](#styles-optimization-options) | `true` |
|
||||
| `fonts` | Enables optimization for fonts. This requires internet access. | `boolean` | [Fonts optimization options](#fonts-optimization-options) | `true` |
|
||||
|
||||
#### Styles optimization options
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Use the element name from the error message to search for places where you're us
|
||||
|
||||
@Component({
|
||||
selector: 'YOUR_STRING',
|
||||
…
|
||||
…
|
||||
})
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -17,10 +17,10 @@ Ensure that all dependencies are properly imported and declared in your NgModule
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
@NgModule({
|
||||
…
|
||||
…
|
||||
imports: [
|
||||
FormsModule,
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ Move all declarations:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
const moduleDefinition = {…}
|
||||
const moduleDefinition = {…}
|
||||
|
||||
@NgModule(moduleDefinition)
|
||||
export class AppModule {
|
||||
@@ -24,7 +24,7 @@ into the decorator:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@NgModule({…})
|
||||
@NgModule({…})
|
||||
export class AppModule {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ Rename your component's selector so that it matches the requirements.
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
encapsulation: ViewEncapsulation.ShadowDom
|
||||
…
|
||||
…
|
||||
})
|
||||
|
||||
</docs-code>
|
||||
@@ -31,7 +31,7 @@ Rename your component's selector so that it matches the requirements.
|
||||
@Component({
|
||||
selector: 'app-comp',
|
||||
encapsulation: ViewEncapsulation.ShadowDom
|
||||
…
|
||||
…
|
||||
})
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -15,7 +15,7 @@ In order to make this reference, the compiler would have to add an import from `
|
||||
|
||||
<docs-code language="text">
|
||||
|
||||
parent.component.ts -> child.component.ts -> parent.component.ts
|
||||
parent.component.ts -> child.component.ts -> parent.component.ts
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -27,7 +27,7 @@ This is known as "remote scoping".
|
||||
|
||||
## Libraries
|
||||
|
||||
Unfortunately, "remote scoping" code is side-effectful —which prevents tree shaking— and cannot be used in libraries.
|
||||
Unfortunately, "remote scoping" code is side-effectful —which prevents tree shaking— and cannot be used in libraries.
|
||||
So when building libraries using the `"compilationMode": "partial"` setting, any component that would require a cyclic import will cause this `NG3003` compiler error to be raised.
|
||||
|
||||
## Debugging the error
|
||||
@@ -38,7 +38,7 @@ For example:
|
||||
<docs-code hideCopy="true">
|
||||
|
||||
The component ChildComponent is used in the template but importing it would create a cycle:
|
||||
/parent.component.ts -> /child.component.ts -> /parent.component.ts
|
||||
/parent.component.ts -> /child.component.ts -> /parent.component.ts
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Any property binding must correspond to either:
|
||||
* A native property on the HTML element, or
|
||||
* An `@Input()` property of a component or directive applied to the element.
|
||||
|
||||
The runtime error for this is `NG0304: '${tagName}' is not a known element: …'`.
|
||||
The runtime error for this is `NG0304: '${tagName}' is not a known element: …'`.
|
||||
|
||||
## Debugging the error
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ For example, if the export not found is `ngForm`, we will need to import `FormsM
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
@NgModule({
|
||||
…
|
||||
…
|
||||
imports: [
|
||||
FormsModule,
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
[Control flow syntax](guide/templates/control-flow) is available from Angular 17 and simplified way to use the control-flow directives like *ngFor, *ngIf and *ngSwitch.
|
||||
|
||||
The new syntax is baked into the template, so you don't need to import `CommonModule` anymore. But wait there is more to it, there is an migration available for migrating all your old code to use new Control Flow Syntax with Angular 17 release. Run the schematic with the following command:
|
||||
The new syntax is baked into the template, so you don't need to import `CommonModule` anymore. But wait there is more to it, there is an migration availble for migrating all your old code to use new Control Flow Syntax with Angular 17 release. Run the schematic with the following command:
|
||||
|
||||
<docs-code language="shell">
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ In the example below, the type of the `NgModule` is `SomeModule`, so the schemat
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@NgModule({…})
|
||||
@NgModule({…})
|
||||
export class MyModule {
|
||||
static forRoot(config: SomeConfig): ModuleWithProviders {
|
||||
return {
|
||||
@@ -31,9 +31,9 @@ export class MyModule {
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@NgModule({…})
|
||||
@NgModule({…})
|
||||
export class MyModule {
|
||||
static forRoot(config: SomeConfig): ModuleWithProviders<SomeModule> {
|
||||
static forRoot(config: SomeConfig): ModuleWithProviders<SomeModule> {
|
||||
return {
|
||||
ngModule: SomeModule,
|
||||
providers: [
|
||||
|
||||
@@ -122,7 +122,7 @@ To help ensure that you have sufficient time and a clear path to update, this is
|
||||
## Compatibility policy
|
||||
|
||||
Angular is a collection of many packages, subprojects, and tools.
|
||||
To prevent accidental use of private APIs and so that you can clearly understand what is covered by the practices described here — we document what is and is not considered our public API surface.
|
||||
To prevent accidental use of private APIs and so that you can clearly understand what is covered by the practices described here — we document what is and is not considered our public API surface.
|
||||
For details, see [Supported Public API Surface of Angular](https://github.com/angular/angular/blob/main/docs/PUBLIC_API.md "Supported Public API Surface of Angular").
|
||||
|
||||
To guarantee backward compatibility of Angular we run a series of checks before we merge any change:
|
||||
|
||||
@@ -9,8 +9,7 @@ This table covers [Angular versions under active support](reference/releases#act
|
||||
|
||||
| Angular | Node.js | TypeScript | RxJS |
|
||||
| ------------------ | ------------------------------------ | -------------- | ------------------ |
|
||||
| 17.3.x | ^18.13.0 \|\| ^20.9.0 | >=5.2.0 <5.5.0 | ^6.5.3 \|\| ^7.4.0 |
|
||||
| 17.1.x \|\| 17.2.x | ^18.13.0 \|\| ^20.9.0 | >=5.2.0 <5.4.0 | ^6.5.3 \|\| ^7.4.0 |
|
||||
| 17.1.0 | ^18.13.0 \|\| ^20.9.0 | >=5.2.0 <5.4.0 | ^6.5.3 \|\| ^7.4.0 |
|
||||
| 17.0.x | ^18.13.0 \|\| ^20.9.0 | >=5.2.0 <5.3.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 |
|
||||
@@ -120,24 +119,24 @@ If you are not using the CLI, add your polyfill scripts directly to the host web
|
||||
For example:
|
||||
|
||||
<docs-code header="src/index.html" language="html">
|
||||
<!-- pre-zone polyfills -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
<script>
|
||||
<!-- pre-zone polyfills -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
<script>
|
||||
/**
|
||||
* you can configure some zone flags which can disable zone interception for some
|
||||
* asynchronous activities to improve startup performance - use these options only
|
||||
* if you know what you are doing as it could result in hard to trace down bugs.
|
||||
* you can configure some zone flags which can disable zone interception for some
|
||||
* asynchronous activities to improve startup performance - use these options only
|
||||
* if you know what you are doing as it could result in hard to trace down bugs.
|
||||
*/
|
||||
// __Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||
// __Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
// __zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
/*
|
||||
* in Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for Edge.
|
||||
* in Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for Edge.
|
||||
*/
|
||||
// __Zone_enable_cross_context_check = true;
|
||||
</script>
|
||||
<!-- zone.js required by Angular -->
|
||||
<script src="node_modules/zone.js/bundles/zone.umd.js"></script>
|
||||
<!-- application polyfills -->
|
||||
</script>
|
||||
<!-- zone.js required by Angular -->
|
||||
<script src="node_modules/zone.js/bundles/zone.umd.js"></script>
|
||||
<!-- application polyfills -->
|
||||
</docs-code>
|
||||
|
||||
@@ -44,13 +44,13 @@ In the following example, the `@Component()` metadata object and the class const
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'app-typical',
|
||||
template: '<div>A typical component for {{data.name}}</div>'
|
||||
template: '<div>A typical component for {{data.name}}</div>'
|
||||
})
|
||||
export class TypicalComponent {
|
||||
@Input() data: TypicalData;
|
||||
constructor(private someService: SomeService) { … }
|
||||
@Input() data: TypicalData;
|
||||
constructor(private someService: SomeService) { … }
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
@@ -104,13 +104,13 @@ Define metadata objects with the following limited syntax:
|
||||
|:--- |:--- |
|
||||
| Literal object | `{cherry: true, apple: true, mincemeat: false}` |
|
||||
| Literal array | `['cherries', 'flour', 'sugar']` |
|
||||
| Spread in literal array | `['apples', 'flour', …]` |
|
||||
| Spread in literal array | `['apples', 'flour', ...]` |
|
||||
| Calls | `bake(ingredients)` |
|
||||
| New | `new Oven()` |
|
||||
| Property access | `pie.slice` |
|
||||
| Array index | `ingredients[0]` |
|
||||
| Identity reference | `Component` |
|
||||
| A template string | <code>`pie is ${multiplier} times better than cake`</code> |
|
||||
| A template string | <code>`pie is ${multiplier} times better than cake`</code> |
|
||||
| Literal string | `'pi'` |
|
||||
| Literal number | `3.14153265` |
|
||||
| Literal boolean | `true` |
|
||||
@@ -128,7 +128,7 @@ HELPFUL: If you want `ngc` to report syntax errors immediately rather than produ
|
||||
<docs-code language="json">
|
||||
|
||||
"angularCompilerOptions": {
|
||||
…
|
||||
…
|
||||
"strictMetadataEmit" : true
|
||||
}
|
||||
|
||||
@@ -145,9 +145,9 @@ Consider the following component decorator:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@Component({
|
||||
…
|
||||
providers: [{provide: server, useFactory: () => new Server()}]
|
||||
@Component({
|
||||
…
|
||||
providers: [{provide: server, useFactory: () => new Server()}]
|
||||
})
|
||||
|
||||
</docs-code>
|
||||
@@ -164,8 +164,8 @@ export function serverFactory() {
|
||||
return new Server();
|
||||
}
|
||||
|
||||
@Component({
|
||||
…
|
||||
@Component({
|
||||
…
|
||||
providers: [{provide: server, useFactory: serverFactory}]
|
||||
})
|
||||
|
||||
@@ -189,14 +189,14 @@ Consider the following component definition:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
const template = '<div>{{hero.name}}</div>';
|
||||
const template = '<div>{{hero.name}}</div>';
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'app-hero',
|
||||
template: template
|
||||
})
|
||||
export class HeroComponent {
|
||||
@Input() hero: Hero;
|
||||
@Input() hero: Hero;
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
@@ -207,12 +207,12 @@ The effect is the same as if you had written:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'app-hero',
|
||||
template: '<div>{{hero.name}}</div>'
|
||||
template: '<div>{{hero.name}}</div>'
|
||||
})
|
||||
export class HeroComponent {
|
||||
@Input() hero: Hero;
|
||||
@Input() hero: Hero;
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
@@ -223,14 +223,14 @@ You can take this example a step further by including the `template` constant in
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
const template = '<div>{{hero.name}}</div>';
|
||||
const template = '<div>{{hero.name}}</div>';
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'app-hero',
|
||||
template: template + '<div>{{hero.title}}</div>'
|
||||
template: template + '<div>{{hero.title}}</div>'
|
||||
})
|
||||
export class HeroComponent {
|
||||
@Input() hero: Hero;
|
||||
@Input() hero: Hero;
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
@@ -239,7 +239,7 @@ The collector reduces this expression to its equivalent *folded* string:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
'<div>{{hero.name}}</div><div>{{hero.title}}</div>'
|
||||
'<div>{{hero.name}}</div><div>{{hero.title}}</div>'
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -309,7 +309,7 @@ For example, consider the following function:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
export function wrapInArray<T>(value: T): T[] {
|
||||
export function wrapInArray<T>(value: T): T[] {
|
||||
return [value];
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ You might use `wrapInArray()` like this:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@NgModule({
|
||||
@NgModule({
|
||||
declarations: wrapInArray(TypicalComponent)
|
||||
})
|
||||
export class TypicalModule {}
|
||||
@@ -332,7 +332,7 @@ The compiler treats this usage as if you had written:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@NgModule({
|
||||
@NgModule({
|
||||
declarations: [TypicalComponent]
|
||||
})
|
||||
export class TypicalModule {}
|
||||
@@ -347,7 +347,7 @@ for these methods to see how macros can simplify configuration of complex [NgMod
|
||||
|
||||
The compiler treats object literals containing the fields `useClass`, `useValue`, `useFactory`, and `data` specially, converting the expression initializing one of these fields into an exported variable that replaces the expression.
|
||||
This process of rewriting these expressions removes all the restrictions on what can be in them because
|
||||
the compiler doesn't need to know the expression's value — it just needs to be able to generate a reference to the value.
|
||||
the compiler doesn't need to know the expression's value —it just needs to be able to generate a reference to the value.
|
||||
|
||||
You might write something like:
|
||||
|
||||
@@ -357,8 +357,8 @@ class TypicalServer {
|
||||
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
providers: [{provide: SERVER, useFactory: () => TypicalServer}]
|
||||
@NgModule({
|
||||
providers: [{provide: SERVER, useFactory: () => TypicalServer}]
|
||||
})
|
||||
export class TypicalModule {}
|
||||
|
||||
@@ -373,10 +373,10 @@ class TypicalServer {
|
||||
|
||||
}
|
||||
|
||||
export const θ0 = () => new TypicalServer();
|
||||
export const θ0 = () => new TypicalServer();
|
||||
|
||||
@NgModule({
|
||||
providers: [{provide: SERVER, useFactory: θ0}]
|
||||
@NgModule({
|
||||
providers: [{provide: SERVER, useFactory: θ0}]
|
||||
})
|
||||
export class TypicalModule {}
|
||||
|
||||
@@ -404,7 +404,7 @@ For example, consider the following component:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: '{{person.addresss.street}}'
|
||||
})
|
||||
@@ -451,7 +451,7 @@ For example, to avoid `Object is possibly 'undefined'` error in the template abo
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: '<span *ngIf="person"> {{person.address.street}} </span>'
|
||||
})
|
||||
@@ -474,9 +474,9 @@ There is no convenient way to describe this constraint to TypeScript and the tem
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: '<span *ngIf="person"> {{person.name}} lives on {{address!.street}} </span>'
|
||||
template: '<span *ngIf="person"> {{person.name}} lives on {{address!.street}} </span>'
|
||||
})
|
||||
class MyComponent {
|
||||
person?: Person;
|
||||
@@ -496,9 +496,9 @@ In this example it is recommended to include the checking of `address` in the `*
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: '<span *ngIf="person && address"> {{person.name}} lives on {{address.street}} </span>'
|
||||
template: '<span *ngIf="person && address"> {{person.name}} lives on {{address.street}} </span>'
|
||||
})
|
||||
class MyComponent {
|
||||
person?: Person;
|
||||
|
||||
@@ -11,13 +11,13 @@ can produce this error, as seen in the following example:
|
||||
|
||||
<docs-code language="typescript">
|
||||
// ERROR
|
||||
export class Fooish { … }
|
||||
…
|
||||
export class Fooish { … }
|
||||
…
|
||||
const prop = typeof Fooish; // typeof is not valid in metadata
|
||||
…
|
||||
…
|
||||
// bracket notation is not valid in metadata
|
||||
{ provide: 'token', useValue: { [prop]: 'value' } };
|
||||
…
|
||||
…
|
||||
</docs-code>
|
||||
|
||||
You can use `typeof` and bracket notation in normal application code.
|
||||
@@ -40,9 +40,9 @@ Here's a `provider` example of the problem.
|
||||
// ERROR
|
||||
let foo: number; // neither exported nor initialized
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: … ,
|
||||
template: … ,
|
||||
providers: [
|
||||
{ provide: Foo, useValue: foo }
|
||||
]
|
||||
@@ -73,9 +73,9 @@ Alternatively, you can fix it by exporting `foo` with the expectation that `foo`
|
||||
// CORRECTED
|
||||
export let foo: number; // exported
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: … ,
|
||||
template: … ,
|
||||
providers: [
|
||||
{ provide: Foo, useValue: foo }
|
||||
]
|
||||
@@ -94,7 +94,7 @@ For example, it doesn't work for the `template` property.
|
||||
// ERROR
|
||||
export let someTemplate: string; // exported but not initialized
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: someTemplate
|
||||
})
|
||||
@@ -120,7 +120,7 @@ The following example tries to set the component's `template` property to the va
|
||||
// ERROR
|
||||
export let someTemplate: string;
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: someTemplate
|
||||
})
|
||||
@@ -135,7 +135,7 @@ You'd also get this error if you imported `someTemplate` from some other module
|
||||
// ERROR - not initialized there either
|
||||
import { someTemplate } from './config';
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: someTemplate
|
||||
})
|
||||
@@ -151,9 +151,9 @@ To correct this error, provide the initial value of the variable in an initializ
|
||||
<docs-code language="typescript">
|
||||
|
||||
// CORRECTED
|
||||
export let someTemplate = '<h1>Greetings from Angular</h1>';
|
||||
export let someTemplate = '<h1>Greetings from Angular</h1>';
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: someTemplate
|
||||
})
|
||||
@@ -175,11 +175,11 @@ For example, you may have defined a class and used it as an injection token in a
|
||||
// ERROR
|
||||
abstract class MyStrategy { }
|
||||
|
||||
…
|
||||
…
|
||||
providers: [
|
||||
{ provide: MyStrategy, useValue: … }
|
||||
{ provide: MyStrategy, useValue: … }
|
||||
]
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -191,11 +191,11 @@ To correct this error, export the referenced class.
|
||||
// CORRECTED
|
||||
export abstract class MyStrategy { }
|
||||
|
||||
…
|
||||
…
|
||||
providers: [
|
||||
{ provide: MyStrategy, useValue: … }
|
||||
{ provide: MyStrategy, useValue: … }
|
||||
]
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -208,13 +208,13 @@ For example, you may have set a providers `useFactory` property to a locally def
|
||||
<docs-code language="typescript">
|
||||
|
||||
// ERROR
|
||||
function myStrategy() { … }
|
||||
function myStrategy() { … }
|
||||
|
||||
…
|
||||
…
|
||||
providers: [
|
||||
{ provide: MyStrategy, useFactory: myStrategy }
|
||||
]
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -224,13 +224,13 @@ To correct this error, export the function.
|
||||
<docs-code language="typescript">
|
||||
|
||||
// CORRECTED
|
||||
export function myStrategy() { … }
|
||||
export function myStrategy() { … }
|
||||
|
||||
…
|
||||
…
|
||||
providers: [
|
||||
{ provide: MyStrategy, useFactory: myStrategy }
|
||||
]
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -244,12 +244,12 @@ For example, you cannot set a provider's `useFactory` to an anonymous function o
|
||||
<docs-code language="typescript">
|
||||
|
||||
// ERROR
|
||||
…
|
||||
…
|
||||
providers: [
|
||||
{ provide: MyStrategy, useFactory: function() { … } },
|
||||
{ provide: OtherStrategy, useFactory: () => { … } }
|
||||
{ provide: MyStrategy, useFactory: function() { … } },
|
||||
{ provide: OtherStrategy, useFactory: () => { … } }
|
||||
]
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -260,11 +260,11 @@ You also get this error if you call a function or method in a provider's `useVal
|
||||
// ERROR
|
||||
import { calculateValue } from './utilities';
|
||||
|
||||
…
|
||||
…
|
||||
providers: [
|
||||
{ provide: SomeValue, useValue: calculateValue() }
|
||||
]
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -275,18 +275,18 @@ To correct this error, export a function from the module and refer to the functi
|
||||
// CORRECTED
|
||||
import { calculateValue } from './utilities';
|
||||
|
||||
export function myStrategy() { … }
|
||||
export function otherStrategy() { … }
|
||||
export function myStrategy() { … }
|
||||
export function otherStrategy() { … }
|
||||
export function someValueFactory() {
|
||||
return calculateValue();
|
||||
}
|
||||
…
|
||||
…
|
||||
providers: [
|
||||
{ provide: MyStrategy, useFactory: myStrategy },
|
||||
{ provide: OtherStrategy, useFactory: otherStrategy },
|
||||
{ provide: SomeValue, useFactory: someValueFactory }
|
||||
]
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -305,12 +305,12 @@ import { configuration } from './configuration';
|
||||
|
||||
// destructured assignment to foo and bar
|
||||
const {foo, bar} = configuration;
|
||||
…
|
||||
…
|
||||
providers: [
|
||||
{provide: Foo, useValue: foo},
|
||||
{provide: Bar, useValue: bar},
|
||||
]
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -320,12 +320,12 @@ To correct this error, refer to non-destructured values.
|
||||
|
||||
// CORRECTED
|
||||
import { configuration } from './configuration';
|
||||
…
|
||||
…
|
||||
providers: [
|
||||
{provide: Foo, useValue: configuration.foo},
|
||||
{provide: Bar, useValue: configuration.bar},
|
||||
]
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -341,9 +341,9 @@ You'll get an error if you reference it in the component constructor, which the
|
||||
<docs-code language="typescript">
|
||||
|
||||
// ERROR
|
||||
@Component({ })
|
||||
@Component({ })
|
||||
export class MyComponent {
|
||||
constructor (private win: Window) { … }
|
||||
constructor (private win: Window) { … }
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
@@ -368,19 +368,19 @@ Here's an illustrative example.
|
||||
<docs-code language="typescript">
|
||||
|
||||
// CORRECTED
|
||||
import { Inject } from '@angular/core';
|
||||
import { Inject } from '@angular/core';
|
||||
|
||||
export const WINDOW = new InjectionToken('Window');
|
||||
export function _window() { return window; }
|
||||
|
||||
@Component({
|
||||
…
|
||||
@Component({
|
||||
…
|
||||
providers: [
|
||||
{ provide: WINDOW, useFactory: _window }
|
||||
]
|
||||
})
|
||||
export class MyComponent {
|
||||
constructor (@Inject(WINDOW) private win: Window) { … }
|
||||
constructor (@Inject(WINDOW) private win: Window) { … }
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
@@ -392,12 +392,12 @@ Angular does something similar with the `DOCUMENT` token so you can inject the b
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
import { Inject } from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject } from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
|
||||
@Component({ … })
|
||||
@Component({ … })
|
||||
export class MyComponent {
|
||||
constructor (@Inject(DOCUMENT) private doc: Document) { … }
|
||||
constructor (@Inject(DOCUMENT) private doc: Document) { … }
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
@@ -439,13 +439,13 @@ enum Colors {
|
||||
Blue = "Blue".length // computed
|
||||
}
|
||||
|
||||
…
|
||||
…
|
||||
providers: [
|
||||
{ provide: BaseColor, useValue: Colors.White } // ok
|
||||
{ provide: DangerColor, useValue: Colors.Red } // ok
|
||||
{ provide: StrongColor, useValue: Colors.Blue } // bad
|
||||
]
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -461,10 +461,10 @@ The compiler encountered a JavaScript ES2015 [tagged template expression](https:
|
||||
|
||||
// ERROR
|
||||
const expression = 'funky';
|
||||
const raw = String.raw`A tagged template ${expression} string`;
|
||||
…
|
||||
template: '<div>' + raw + '</div>'
|
||||
…
|
||||
const raw = String.raw`A tagged template ${expression} string`;
|
||||
…
|
||||
template: '<div>' + raw + '</div>'
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -27,11 +27,11 @@ You can determine which builder is being used for a particular project by lookin
|
||||
// `ng build` invokes the Architect target named `build`.
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:application",
|
||||
…
|
||||
…
|
||||
},
|
||||
"serve": { … }
|
||||
"test": { … }
|
||||
…
|
||||
"serve": { … }
|
||||
"test": { … }
|
||||
…
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,10 +55,10 @@ Define your size boundaries in the CLI configuration file, `angular.json`, in a
|
||||
<docs-code language="json">
|
||||
|
||||
{
|
||||
…
|
||||
…
|
||||
"configurations": {
|
||||
"production": {
|
||||
…
|
||||
…
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
@@ -120,9 +120,9 @@ If the best option is to use a CommonJS dependency, you can disable these warnin
|
||||
"allowedCommonJsDependencies": [
|
||||
"lodash"
|
||||
]
|
||||
…
|
||||
…
|
||||
}
|
||||
…
|
||||
…
|
||||
},
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -179,17 +179,17 @@ By default, for example, the `ng build` command runs the builder `@angular-devki
|
||||
|
||||
<docs-code header="angular.json" language="json">
|
||||
|
||||
…
|
||||
…
|
||||
|
||||
"myApp": {
|
||||
…
|
||||
…
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/myApp",
|
||||
"index": "src/index.html",
|
||||
…
|
||||
…
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
@@ -201,15 +201,15 @@ By default, for example, the `ng build` command runs the builder `@angular-devki
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
…
|
||||
…
|
||||
}
|
||||
}
|
||||
},
|
||||
…
|
||||
…
|
||||
}
|
||||
}
|
||||
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -265,7 +265,7 @@ You can publish the builder to npm (see [Publishing your Library](tools/librarie
|
||||
|
||||
<docs-code language="shell">
|
||||
|
||||
npm install @example/copy-file
|
||||
npm install @example/copy-file
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Angular CLI builders support a `configurations` object, which allows overwriting
|
||||
}
|
||||
}
|
||||
},
|
||||
…
|
||||
…
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,7 +154,7 @@ You can change or add file replacements for specific build targets by editing th
|
||||
"with": "src/environments/environment.development.ts"
|
||||
}
|
||||
],
|
||||
…
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -165,8 +165,8 @@ To add a staging environment, create a copy of `src/environments/environment.ts`
|
||||
<docs-code language="json">
|
||||
|
||||
"configurations": {
|
||||
"development": { … },
|
||||
"production": { … },
|
||||
"development": { … },
|
||||
"production": { … },
|
||||
"staging": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
@@ -197,7 +197,7 @@ You can also configure `ng serve` to use the targeted build configuration if you
|
||||
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": { … },
|
||||
"options": { … },
|
||||
"configurations": {
|
||||
"development": {
|
||||
// Use the `development` configuration of the `build` target.
|
||||
|
||||
@@ -38,12 +38,12 @@ A `RuleFactory` object defines a higher-order function that creates a `Rule`.
|
||||
|
||||
<docs-code header="index.ts" language="typescript">
|
||||
|
||||
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
|
||||
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
|
||||
|
||||
// You don't have to export the function as default.
|
||||
// You can also have more than one rule factory per file.
|
||||
export function helloWorld(_options: any): Rule {
|
||||
return (tree: Tree,_context: SchematicContext) => {
|
||||
return (tree: Tree,_context: SchematicContext) => {
|
||||
return tree;
|
||||
};
|
||||
}
|
||||
@@ -66,7 +66,7 @@ import {
|
||||
normalize,
|
||||
parseJsonAst,
|
||||
strings,
|
||||
} from '@angular-devkit/core';
|
||||
} from '@angular-devkit/core';
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -154,7 +154,7 @@ In the short form, the type is inferred from the property's type and constraints
|
||||
| "type": "string" | input |
|
||||
| "type": "number" | input \(only valid numbers accepted\) |
|
||||
| "type": "integer" | input \(only valid numbers accepted\) |
|
||||
| "enum": […] | list \(enum members become list selections\) |
|
||||
| "enum": […] | list \(enum members become list selections\) |
|
||||
|
||||
In the following example, the property takes an enumerated value, so the schematic automatically chooses the list type, and creates a menu from the possible values.
|
||||
|
||||
@@ -268,7 +268,7 @@ Using Node 6.9 or later, install the Schematics command line tool globally:
|
||||
|
||||
<docs-code language="shell">
|
||||
|
||||
npm install -g @angular-devkit/schematics-cli
|
||||
npm install -g @angular-devkit/schematics-cli
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -316,7 +316,7 @@ Provide the path to the project folder, the schematic name, and any mandatory op
|
||||
|
||||
<docs-code language="shell">
|
||||
|
||||
schematics <path-to-schematics-project>:<schematics-name> --<required-option>=<value>
|
||||
schematics <path-to-schematics-project>:<schematics-name> --<required-option>=<value>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -352,8 +352,8 @@ Each schematic is created with a name, description, and factory function.
|
||||
<docs-code language="json">
|
||||
|
||||
{
|
||||
"$schema":
|
||||
"../node_modules/@angular-devkit/schematics/collection-schema.json",
|
||||
"$schema":
|
||||
"../node_modules/@angular-devkit/schematics/collection-schema.json",
|
||||
"schematics": {
|
||||
"hello-world": {
|
||||
"description": "A blank schematic.",
|
||||
|
||||
@@ -147,13 +147,13 @@ Schematic templates support special syntax to execute code and variable substitu
|
||||
|
||||
<docs-code lang="typescript" header="projects/my-lib/schematics/my-service/files/__name@dasherize__.service.ts.template (Schematic Template)">
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable({
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class <%= classify(name) %>Service {
|
||||
export class <%= classify(name) %>Service {
|
||||
constructor(private http: HttpClient) { }
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ The following command uses one of these schematics to render an Angular Material
|
||||
|
||||
<docs-code language="shell">
|
||||
|
||||
ng generate @angular/material:table <component-name>
|
||||
ng generate @angular/material:table <component-name>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -97,11 +97,11 @@ We analyzed your package.json, there are some packages to update:
|
||||
|
||||
Name Version Command to update
|
||||
‐-------------------------------------------------------------------------------
|
||||
@angular/cdk 7.2.2 -> 7.3.1 ng update @angular/cdk
|
||||
@angular/cli 7.2.3 -> 7.3.0 ng update @angular/cli
|
||||
@angular/core 7.2.2 -> 7.2.3 ng update @angular/core
|
||||
@angular/material 7.2.2 -> 7.3.1 ng update @angular/material
|
||||
rxjs 6.3.3 -> 6.4.0 ng update rxjs
|
||||
@angular/cdk 7.2.2 -> 7.3.1 ng update @angular/cdk
|
||||
@angular/cli 7.2.3 -> 7.3.0 ng update @angular/cli
|
||||
@angular/core 7.2.2 -> 7.2.3 ng update @angular/core
|
||||
@angular/material 7.2.2 -> 7.3.1 ng update @angular/material
|
||||
rxjs 6.3.3 -> 6.4.0 ng update rxjs
|
||||
|
||||
There might be additional packages that are outdated.
|
||||
Run "ng update --all" to try to update all at the same time.
|
||||
@@ -122,7 +122,7 @@ If you create a new version of your library that introduces potential breaking c
|
||||
For example, suppose you want to update the Angular Material library.
|
||||
|
||||
<docs-code language="shell">
|
||||
ng update @angular/material
|
||||
ng update @angular/material
|
||||
</docs-code>
|
||||
|
||||
This command updates both `@angular/material` and its dependency `@angular/cdk` in your workspace's `package.json`.
|
||||
|
||||
@@ -76,10 +76,10 @@ interface User {
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<div *ngFor="let user of users">
|
||||
<h2>{{config.title}}</h2>
|
||||
<span>City: {{user.address.city}}</span>
|
||||
</div>
|
||||
<div *ngFor="let user of users">
|
||||
<h2>{{config.title}}</h2>
|
||||
<span>City: {{user.address.city}}</span>
|
||||
</div>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -116,7 +116,7 @@ Unless otherwise commented, each following option is set to the value for `stric
|
||||
| `strictInputTypes` | Whether the assignability of a binding expression to the `@Input()` field is checked. Also affects the inference of directive generic types. |
|
||||
| `strictInputAccessModifiers` | Whether access modifiers such as `private`/`protected`/`readonly` are honored when assigning a binding expression to an `@Input()`. If disabled, the access modifiers of the `@Input` are ignored; only the type is checked. This option is `false` by default, even with `strictTemplates` set to `true`. |
|
||||
| `strictNullInputTypes` | Whether `strictNullChecks` is honored when checking `@Input()` bindings \(per `strictInputTypes`\). Turning this off can be useful when using a library that was not built with `strictNullChecks` in mind. |
|
||||
| `strictAttributeTypes` | Whether to check `@Input()` bindings that are made using text attributes. For example, <docs-code hideCopy language="html"> <input matInput disabled="true"> </docs-code> \(setting the `disabled` property to the string `'true'`\) vs <docs-code hideCopy language="html"> <input matInput [disabled]="true"> </docs-code> \(setting the `disabled` property to the boolean `true`\). |
|
||||
| `strictAttributeTypes` | Whether to check `@Input()` bindings that are made using text attributes. For example, <docs-code hideCopy language="html"> <input matInput disabled="true"> </docs-code> \(setting the `disabled` property to the string `'true'`\) vs <docs-code hideCopy language="html"> <input matInput [disabled]="true"> </docs-code> \(setting the `disabled` property to the boolean `true`\). |
|
||||
| `strictSafeNavigationTypes` | Whether the return type of safe navigation operations \(for example, `user?.name` will be correctly inferred based on the type of `user`\). If disabled, `user?.name` will be of type `any`. |
|
||||
| `strictDomLocalRefTypes` | Whether local references to DOM elements will have the correct type. If disabled `ref` will be of type `any` for `<input #ref>`. |
|
||||
| `strictOutputEventTypes` | Whether `$event` will have the correct type for event bindings to component/directive an `@Output()`, or to animation events. If disabled, it will be `any`. |
|
||||
@@ -143,12 +143,12 @@ export interface User {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'user-detail',
|
||||
template: '{{ user.name }}',
|
||||
})
|
||||
export class UserDetailComponent {
|
||||
@Input() user: User;
|
||||
@Input() user: User;
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
@@ -157,12 +157,12 @@ The `AppComponent` template uses this component as follows:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: '<user-detail [user]="selectedUser"></user-detail>',
|
||||
template: '<user-detail [user]="selectedUser"></user-detail>',
|
||||
})
|
||||
export class AppComponent {
|
||||
selectedUser: User | null = null;
|
||||
selectedUser: User | null = null;
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
@@ -189,7 +189,7 @@ For example:
|
||||
* Using the `async` pipe with an Observable which you know will emit synchronously.
|
||||
|
||||
The `async` pipe currently assumes that the Observable it subscribes to can be asynchronous, which means that it's possible that there is no value available yet.
|
||||
In that case, it still has to return something —which is `null`.
|
||||
In that case, it still has to return something —which is `null`.
|
||||
In other words, the return type of the `async` pipe includes `null`, which might result in errors in situations where the Observable is known to emit a non-nullable value synchronously.
|
||||
|
||||
There are two potential workarounds to the preceding issues:
|
||||
@@ -198,7 +198,7 @@ There are two potential workarounds to the preceding issues:
|
||||
|
||||
<docs-code hideCopy language="html">
|
||||
|
||||
<user-detail [user]="user!"></user-detail>
|
||||
<user-detail [user]="user!"></user-detail>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -207,7 +207,7 @@ There are two potential workarounds to the preceding issues:
|
||||
|
||||
<docs-code hideCopy language="html">
|
||||
|
||||
<user-detail [user]="(user$ | async)!"></user-detail>
|
||||
<user-detail [user]="(user$ | async)!"></user-detail>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -233,18 +233,18 @@ Consider the following directive:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'submit-button',
|
||||
template: `
|
||||
<div class="wrapper">
|
||||
<button [disabled]="disabled">Submit</button>
|
||||
</div>
|
||||
`,
|
||||
template: `
|
||||
<div class="wrapper">
|
||||
<button [disabled]="disabled">Submit</button>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
class SubmitButton {
|
||||
private _disabled: boolean;
|
||||
|
||||
@Input()
|
||||
@Input()
|
||||
get disabled(): boolean {
|
||||
return this._disabled;
|
||||
}
|
||||
@@ -262,7 +262,7 @@ But, suppose a consumer uses this input in the template as an attribute:
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<submit-button disabled></submit-button>
|
||||
<submit-button disabled></submit-button>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -270,7 +270,7 @@ This has the same effect as the binding:
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
<submit-button [disabled]="''"></submit-button>
|
||||
<submit-button [disabled]="''"></submit-button>
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -280,7 +280,7 @@ Angular component libraries that deal with this problem often "coerce" the value
|
||||
<docs-code language="typescript">
|
||||
|
||||
set disabled(value: boolean) {
|
||||
this._disabled = (value === '') || value;
|
||||
this._disabled = (value === '') || value;
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
@@ -298,16 +298,16 @@ Enable this by adding a static property with the `ngAcceptInputType_` prefix to
|
||||
class SubmitButton {
|
||||
private _disabled: boolean;
|
||||
|
||||
@Input()
|
||||
@Input()
|
||||
get disabled(): boolean {
|
||||
return this._disabled;
|
||||
}
|
||||
|
||||
set disabled(value: boolean) {
|
||||
this._disabled = (value === '') || value;
|
||||
this._disabled = (value === '') || value;
|
||||
}
|
||||
|
||||
static ngAcceptInputType_disabled: boolean|'';
|
||||
static ngAcceptInputType_disabled: boolean|'';
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
@@ -330,9 +330,9 @@ In the following example, casting `person` to the `any` type suppresses the erro
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
@Component({
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: '{{$any(person).address.street}}'
|
||||
template: '{{$any(person).address.street}}'
|
||||
})
|
||||
class MyComponent {
|
||||
person?: Person;
|
||||
|
||||
@@ -101,7 +101,7 @@ Starting with TypeScript 2.3, TypeScript has a plug-in model that the language s
|
||||
|
||||
<docs-code language="shell">
|
||||
|
||||
npm install --save-dev @angular/language-service
|
||||
npm install --save-dev @angular/language-service
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -110,7 +110,7 @@ Starting with TypeScript 2.3, TypeScript has a plug-in model that the language s
|
||||
<docs-code header="tsconfig.json" language="json">
|
||||
|
||||
"plugins": [
|
||||
{"name": "@angular/language-service"}
|
||||
{"name": "@angular/language-service"}
|
||||
]
|
||||
|
||||
</docs-code>
|
||||
@@ -119,7 +119,7 @@ Starting with TypeScript 2.3, TypeScript has a plug-in model that the language s
|
||||
|
||||
<docs-code header="Sublime Text user preferences" language="json">
|
||||
|
||||
"typescript-tsdk": "<path to your folder>/node_modules/typescript/lib"
|
||||
"typescript-tsdk": "<path to your folder>/node_modules/typescript/lib"
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -127,7 +127,7 @@ This lets the Angular Language Service provide diagnostics and completions in `.
|
||||
|
||||
### Eclipse IDE
|
||||
|
||||
Either directly install the "Eclipse IDE for Web and JavaScript developers" package which comes with the Angular Language Server included, or from other Eclipse IDE packages, use Help > Eclipse Marketplace to find and install [Eclipse Wild Web Developer](https://marketplace.eclipse.org/content/wild-web-developer-html-css-javascript-typescript-nodejs-angular-json-yaml-kubernetes-xml).
|
||||
Either directly install the "Eclipse IDE for Web and JavaScript developers" package which comes with the Angular Language Server included, or from other Eclipse IDE packages, use Help > Eclipse Marketplace to find and install [Eclipse Wild Web Developer](https://marketplace.eclipse.org/content/wild-web-developer-html-css-javascript-typescript-nodejs-angular-json-yaml-kubernetes-xml).
|
||||
|
||||
## How the Language Service works
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ Secondary entrypoints can be resolved via the `"exports"` field of the `package.
|
||||
|
||||
The README file in the Markdown format that is used to display description of a package on npm and GitHub.
|
||||
|
||||
Example README content of @angular/core package:
|
||||
Example README content of @angular/core package:
|
||||
|
||||
<docs-code language="html">
|
||||
|
||||
@@ -212,7 +212,7 @@ To partially compile Angular code, use the `compilationMode` flag in the `angula
|
||||
<docs-code language="javascript">
|
||||
|
||||
{
|
||||
…
|
||||
…
|
||||
"angularCompilerOptions": {
|
||||
"compilationMode": "partial",
|
||||
}
|
||||
@@ -247,13 +247,13 @@ To generate a flattened ES Module index file, use the following configuration op
|
||||
|
||||
{
|
||||
"compilerOptions": {
|
||||
…
|
||||
…
|
||||
"module": "esnext",
|
||||
"target": "es2022",
|
||||
…
|
||||
…
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
…
|
||||
…
|
||||
"flatModuleOutFile": "my-ui-lib.js",
|
||||
"flatModuleId": "my-ui-lib"
|
||||
}
|
||||
@@ -386,7 +386,7 @@ These module IDs are usually considered to be private APIs that can change over
|
||||
### Top-Level import
|
||||
|
||||
An import coming from an entry point.
|
||||
The available top-level imports are what define the public API and are exposed in "@angular/name" modules, such as `@angular/core` or `@angular/common`.
|
||||
The available top-level imports are what define the public API and are exposed in "@angular/name" modules, such as `@angular/core` or `@angular/common`.
|
||||
|
||||
### Tree-shaking
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ When you generate a new library, the workspace configuration file, `angular.json
|
||||
<docs-code>
|
||||
|
||||
"projects": {
|
||||
…
|
||||
…
|
||||
"my-lib": {
|
||||
"root": "projects/my-lib",
|
||||
"sourceRoot": "projects/my-lib/src",
|
||||
@@ -49,8 +49,8 @@ When you generate a new library, the workspace configuration file, `angular.json
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
…
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
…
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ For example, suppose you have a library named `d3`:
|
||||
<docs-code language="shell">
|
||||
|
||||
npm install d3 --save
|
||||
npm install @types/d3 --save-dev
|
||||
npm install @types/d3 --save-dev
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -128,7 +128,7 @@ The following code snippet is an example import statement.
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
import * as $ from 'jquery';
|
||||
import * as $ from 'jquery';
|
||||
|
||||
</docs-code>
|
||||
|
||||
@@ -154,7 +154,7 @@ Some scripts extend other libraries; for instance with JQuery plugins:
|
||||
|
||||
<docs-code language="typescript">
|
||||
|
||||
$('.test').myPlugin();
|
||||
$('.test').myPlugin();
|
||||
|
||||
</docs-code>
|
||||
|
||||
|
||||
+3108
-1537
File diff suppressed because it is too large
Load Diff
@@ -9,21 +9,21 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^17.3.0-rc",
|
||||
"@angular/common": "^17.3.0-rc",
|
||||
"@angular/compiler": "^17.3.0-rc",
|
||||
"@angular/core": "^17.3.0-rc",
|
||||
"@angular/forms": "^17.3.0-rc",
|
||||
"@angular/platform-browser": "^17.3.0-rc",
|
||||
"@angular/router": "^17.3.0-rc",
|
||||
"@angular/animations": "^17.2.0",
|
||||
"@angular/common": "^17.2.0",
|
||||
"@angular/compiler": "^17.2.0",
|
||||
"@angular/core": "^17.2.0",
|
||||
"@angular/forms": "^17.2.0",
|
||||
"@angular/platform-browser": "^17.2.0",
|
||||
"@angular/router": "^17.2.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^17.3.0-rc",
|
||||
"@angular/cli": "^17.3.0-rc",
|
||||
"@angular/compiler-cli": "^17.3.0-rc",
|
||||
"@angular-devkit/build-angular": "^17.2.0",
|
||||
"@angular/cli": "^17.2.0",
|
||||
"@angular/compiler-cli": "^17.2.0",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"@types/node": "^16.11.35",
|
||||
"copyfiles": "^2.4.1",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user