mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
Compare commits
293 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4736c6d133 | |||
| 327bae473b | |||
| 27e6936912 | |||
| ce9e67932c | |||
| b7af42433c | |||
| bba82754c3 | |||
| b6c0f13ee2 | |||
| 801b8c219e | |||
| 9ec3cd0166 | |||
| f25e77b83e | |||
| 81892b1676 | |||
| 9209678719 | |||
| 0ad308ef26 | |||
| 182138e74b | |||
| 8e44f07ddf | |||
| 76f7c5c1b7 | |||
| acea887f16 | |||
| 20ab57abc4 | |||
| 4c7964c970 | |||
| baa6c3c514 | |||
| 1ed8ec6d90 | |||
| 9774ebe1da | |||
| c421d8a9d4 | |||
| faf922b24e | |||
| 5941419cd4 | |||
| 418a35f3fb | |||
| b10e031f52 | |||
| d83dda560f | |||
| 8734b8fd34 | |||
| 41bd844b4e | |||
| a7ef3aa170 | |||
| fc5e032be2 | |||
| 2a7089bdfc | |||
| 2f1530b5f3 | |||
| 349f24af56 | |||
| 45badde88c | |||
| d0d83960f3 | |||
| 5a93df9f18 | |||
| 71f8bca9a7 | |||
| 84f70cc1f1 | |||
| 9d36a2d998 | |||
| 99bf2cd524 | |||
| 7725b70a0a | |||
| a5c3857a7b | |||
| 5e0d2bc143 | |||
| b86a81136d | |||
| 0fa674ba50 | |||
| bd4dbdd2bd | |||
| 436111f661 | |||
| c21b459ba6 | |||
| ec5807cbdc | |||
| f978e9caf1 | |||
| 760e284428 | |||
| 3818436ebc | |||
| c9f27b434a | |||
| 0e6fbfb758 | |||
| 4c50e1e7cb | |||
| 82bbcde843 | |||
| 266ad40e62 | |||
| 4261fd367e | |||
| 6250269f1f | |||
| 3eea50da64 | |||
| e5d58d250d | |||
| ac4e8f7bca | |||
| 51ac883167 | |||
| 9bb3446e35 | |||
| 04d77d5a1c | |||
| 1ca24cb936 | |||
| 967bbc1e3e | |||
| 507d83d5ed | |||
| 4a33efaa3e | |||
| 5530c5e505 | |||
| ce094b227c | |||
| 9258160598 | |||
| 3ee861835a | |||
| 9cd633e1b8 | |||
| 75db462d8b | |||
| c3d077cca1 | |||
| af0eb846a5 | |||
| 544aedee6f | |||
| add11c6854 | |||
| 5083d893a9 | |||
| 826861b1fa | |||
| 9cb003ac3d | |||
| efb9eb4fa9 | |||
| 79a29e4f14 | |||
| eda03d4b89 | |||
| 8979fba2c5 | |||
| d5ee04edc1 | |||
| 87921d7fff | |||
| d38135a12d | |||
| 775476b9ac | |||
| 5cf14da35c | |||
| aeeb38a546 | |||
| 2c66afe857 | |||
| a19e214cbe | |||
| d4c103ae08 | |||
| 39b7bdabec | |||
| 99df5a8ba2 | |||
| 8ae4783d9b | |||
| cc57d4c499 | |||
| 8c6f261fa3 | |||
| c67cbe98a6 | |||
| 9bf9864e79 | |||
| a3b1dc005d | |||
| 8bd9ad02a4 | |||
| 8a670e6bc5 | |||
| afdcff3f71 | |||
| 051c140cc3 | |||
| c77ebb6f51 | |||
| b955999d29 | |||
| 268a26f1b6 | |||
| ca8969b946 | |||
| ce231fb271 | |||
| 888360a6b0 | |||
| 1713d31026 | |||
| 4390d09d58 | |||
| 7676d8fc2d | |||
| e9e8960e76 | |||
| 766548c3ec | |||
| 545fb0d88b | |||
| 9a2295fcee | |||
| d0ae5561b0 | |||
| 9d6effcec9 | |||
| 5587dde5d5 | |||
| 650101e19d | |||
| 36e8f4d5c8 | |||
| 766db6a069 | |||
| 5826d8cb52 | |||
| a7c1115c3d | |||
| 5c0004bb62 | |||
| 9f0691577e | |||
| 4d2a8005e8 | |||
| 13404d5107 | |||
| 68d51f08a3 | |||
| 422e9754b0 | |||
| 80d1094a4e | |||
| 53427d875d | |||
| 9cb1d27406 | |||
| ee0412fb29 | |||
| 05e7bf8734 | |||
| 16eba152c4 | |||
| 4ac78fb846 | |||
| 5ba2a48f49 | |||
| 88f0545e8e | |||
| eb9a5f5bbe | |||
| 158ceaf062 | |||
| 816ddf4539 | |||
| f4e9768da2 | |||
| 7b67ad2fc5 | |||
| 129c973934 | |||
| bc429baa92 | |||
| a84beaa4a7 | |||
| fd45d03d2f | |||
| 949dec26b8 | |||
| fc034137ab | |||
| ca60d9dd3f | |||
| 10851d27cc | |||
| d10dc5c85c | |||
| cb95e2f8ab | |||
| eb0ccfc40c | |||
| a8a20ad238 | |||
| e53d02df85 | |||
| 109df125c8 | |||
| 17f2181299 | |||
| 0bcea6c928 | |||
| 2c325d46b0 | |||
| 54a8fc3b19 | |||
| 555696635e | |||
| 878f581961 | |||
| 9cef0d210f | |||
| 346a555e93 | |||
| fa837a393e | |||
| 4d043992e5 | |||
| 2abcb040eb | |||
| 67f0cf5fc8 | |||
| 2f9d94bc4a | |||
| ee76001431 | |||
| b63afb9e93 | |||
| 658fb0a17f | |||
| f8aa778b70 | |||
| 60ed00a601 | |||
| c7ff3d158a | |||
| aeb20f95d2 | |||
| 708ba8115f | |||
| fb5a28858d | |||
| 5b67c94775 | |||
| b478dfbfda | |||
| 75d1cae616 | |||
| 53fe455630 | |||
| 1470b7d40e | |||
| 76631995e1 | |||
| 519e781701 | |||
| 1af2be9b23 | |||
| a893f0b60d | |||
| 93ce4d0483 | |||
| ed271ebb37 | |||
| 6734b59b35 | |||
| 789326d483 | |||
| 4b63716b4a | |||
| 308b194ee3 | |||
| 62510a7b4d | |||
| ece2deeab6 | |||
| 4d8d324ea6 | |||
| 3253576db8 | |||
| 365fd50407 | |||
| d1d9f5569f | |||
| 7763387253 | |||
| 0ec68a2a40 | |||
| 2ad5dcf3f0 | |||
| 9aff43b5e8 | |||
| fa46844f5c | |||
| cd00ec582b | |||
| 821012d0f7 | |||
| 8958e0bf70 | |||
| 4bb332ef08 | |||
| 64f202cab9 | |||
| cf34d2b87f | |||
| ec4483c471 | |||
| 1f7e81aef9 | |||
| cb433af0e1 | |||
| 3cf70e26ba | |||
| 2b7bad5151 | |||
| 78d4ad20e6 | |||
| c2149dfaa8 | |||
| 99e9474aa2 | |||
| 766bdf3207 | |||
| 2a1ea5a22b | |||
| 529a5f434d | |||
| e70228afa9 | |||
| 4ab3a9afad | |||
| 1f5ab960ef | |||
| 860eccef48 | |||
| e61ccd2ac5 | |||
| 80e5a0a03d | |||
| c0788200e2 | |||
| 42318e7c3d | |||
| 33dc072b70 | |||
| 209632e64d | |||
| e78dd31cea | |||
| 91029aa082 | |||
| 52296bc29d | |||
| 64862cbff2 | |||
| 90bbc68d44 | |||
| a5cc82ee84 | |||
| 855b8e046c | |||
| 35e8184935 | |||
| 74506e76a8 | |||
| c22c5c4543 | |||
| 5d41ab9cd1 | |||
| 243ccce624 | |||
| e8badecf4f | |||
| cdfcb779df | |||
| ac395d0f68 | |||
| e75a9a4d83 | |||
| 41f28f88b1 | |||
| 7df0a8a278 | |||
| 9889346620 | |||
| 39a50f9a8d | |||
| 1f77083a2d | |||
| bb35414a38 | |||
| fcfb42a8ba | |||
| 57e54e29e7 | |||
| 2909e9817d | |||
| 619f3c8792 | |||
| 0ee1a1419d | |||
| f386a04c9d | |||
| 492e03f699 | |||
| ba9ddd7ac2 | |||
| 5d23e601d1 | |||
| a7872ca77a | |||
| 10314787d6 | |||
| 40a94b3ab6 | |||
| 1f129f114e | |||
| 962934bc4f | |||
| 6ce8fc8637 | |||
| e82173e8c4 | |||
| b6a7d509fe | |||
| 01722ee637 | |||
| 7225485311 | |||
| a45e69f627 | |||
| a7d6c64a47 | |||
| 2f7c7b3833 | |||
| 0daa1ea19d | |||
| 658ae699d8 | |||
| 9cf6b9369e | |||
| 9ea0d69275 | |||
| f1991d49b0 | |||
| 198f2ff5f2 | |||
| 8d37ed035c | |||
| 365955322f | |||
| d870856840 | |||
| 7bfa3610c5 |
@@ -65,6 +65,13 @@ build:aio_local_deps --workspace_status_command="yarn -s --cwd aio local-workspa
|
||||
build:snapshot-build --workspace_status_command="yarn -s ng-dev release build-env-stamp --mode=snapshot"
|
||||
build:snapshot-build --stamp
|
||||
|
||||
# Angular DevTools for Firefox releases *cannot* be stamped and `--config snapshot-build-firefox` is a no-op.
|
||||
# This is because Mozilla requires add-on source code to be uploaded and then they manually reproduce the build.
|
||||
# If we stamp the build based on Git information such as the current commit, then reproducing the build would require
|
||||
# uploading the entire `.git` directory. We already must upload the entire monorepo, and uploading `.git` as well
|
||||
# exceeds the max source file size. To address this, we just *don't* stamp Firefox builds of Angular DevTools.
|
||||
build:snapshot-build-firefox --nostamp
|
||||
|
||||
##########################################################
|
||||
# AIO architect build configuration #
|
||||
# See aio/angular.json for available configurations. #
|
||||
|
||||
@@ -4,7 +4,7 @@ description: 'Installs the dependencies using Yarn'
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4
|
||||
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4
|
||||
with:
|
||||
path: |
|
||||
./node_modules/
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4
|
||||
with:
|
||||
token: '${{secrets.GITHUB_TOKEN}}'
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# This workflow builds the AIO previews for pull requests when a certain label is applied.
|
||||
# The actual deployment happens as part of a dedicated second workflow to avoid security
|
||||
# issues where the building would otherwise occur in an authorized context where secrets
|
||||
# could be leaked. More details can be found here:
|
||||
|
||||
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
|
||||
|
||||
name: Build AIO app for preview deployment
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [synchronize, labeled]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
aio-build:
|
||||
runs-on: ubuntu-latest
|
||||
# We only want to build and deploy the AIO app if the `aio: preview` label has been
|
||||
# added, or if the label is already applied and new changes have been made in the PR.
|
||||
if: |
|
||||
(github.event.action == 'labeled' && github.event.label.name == 'aio: preview') ||
|
||||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'aio: preview'))
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- uses: ./.github/actions/yarn-install
|
||||
|
||||
- uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
bazelrc: ./.bazelrc.user
|
||||
|
||||
# Build the web package. Note: We run Bazel from a low-resource Github action container,
|
||||
# so we manually need to instruct Bazel to run more actions concurrently as by default
|
||||
# the number of concurrent actions is determined based on the host resources.
|
||||
- run: bazel build //aio:build --jobs=32 --announce_rc --verbose_failures
|
||||
|
||||
- uses: angular/dev-infra/github-actions/previews/pack-and-upload-artifact@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
workflow-artifact-name: 'aio'
|
||||
pull-number: '${{github.event.pull_request.number}}'
|
||||
artifact-build-revision: '${{github.event.pull_request.head.sha}}'
|
||||
deploy-directory: './dist/bin/aio/build'
|
||||
@@ -0,0 +1,44 @@
|
||||
# This workflow runs whenever the AIO build workflow has completed. Deployment happens
|
||||
# as part of a dedicated second workflow to avoid security issues where the building would
|
||||
# otherwise occur in an authorized context where secrets could be leaked.
|
||||
#
|
||||
# More details can be found here:
|
||||
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
|
||||
|
||||
name: Deploying AIO preview to Firebase
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ['Build AIO app for preview deployment']
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
# Needed in order to be able to comment on the pull request.
|
||||
pull-requests: write
|
||||
|
||||
env:
|
||||
PREVIEW_PROJECT: ng-dev-previews
|
||||
PREVIEW_SITE: ng-dev-previews-fw
|
||||
|
||||
jobs:
|
||||
aio-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
|
||||
- name: Configure Firebase deploy target
|
||||
working-directory: aio/
|
||||
run: |
|
||||
# We can use `npx` as the Firebase deploy actions uses it too.
|
||||
npx -y firebase-tools@latest target:clear --project ${{env.PREVIEW_PROJECT}} hosting aio
|
||||
npx -y firebase-tools@latest target:apply --project ${{env.PREVIEW_PROJECT}} hosting aio ${{env.PREVIEW_SITE}}
|
||||
|
||||
- uses: angular/dev-infra/github-actions/previews/upload-artifacts-to-firebase@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
github-token: '${{secrets.GITHUB_TOKEN}}'
|
||||
workflow-artifact-name: 'aio'
|
||||
firebase-config-dir: './aio/'
|
||||
firebase-public-dir: './aio/dist'
|
||||
firebase-project-id: '${{env.PREVIEW_PROJECT}}'
|
||||
firebase-service-key: '${{secrets.FIREBASE_PREVIEW_SERVICE_TOKEN}}'
|
||||
@@ -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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
+112
-24
@@ -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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
@@ -35,6 +35,8 @@ jobs:
|
||||
run: yarn install --frozen-lockfile --cwd aio
|
||||
- name: Check code lint
|
||||
run: yarn -s tslint
|
||||
- name: Check code lint in aio
|
||||
run: yarn -s --cwd aio lint
|
||||
- name: Check for circular dependencies
|
||||
run: yarn -s ts-circular-deps:check
|
||||
- name: Validate pull approve configuration
|
||||
@@ -58,13 +60,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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Run unit tests
|
||||
@@ -76,46 +78,132 @@ 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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile --network-timeout 100000
|
||||
- name: Run CI tests for framework
|
||||
run: yarn test:ci
|
||||
|
||||
aio:
|
||||
runs-on: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Install node modules for aio
|
||||
run: yarn install --cwd aio --frozen-lockfile
|
||||
- name: Run AIO tests with upstream packages
|
||||
run: yarn --cwd aio test:ci
|
||||
- name: Check generated bundle sizes
|
||||
run: yarn --cwd aio payload-size
|
||||
|
||||
adev:
|
||||
runs-on:
|
||||
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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Build adev to ensure it continues to work
|
||||
run: yarn bazel test --config=aio_local_deps //adev:test
|
||||
|
||||
aio-local:
|
||||
runs-on:
|
||||
labels: ubuntu-latest-4core
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
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@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Install node modules
|
||||
run: yarn install --cwd aio --frozen-lockfile
|
||||
- name: Run AIO tests with local packages
|
||||
run: yarn --cwd aio test-local:ci
|
||||
- name: Check generated bundle sizes
|
||||
run: yarn --cwd aio payload-size aio-local
|
||||
|
||||
aio-deploy:
|
||||
needs: [aio]
|
||||
if: needs.aio.result == 'success' && github.event_name == 'push'
|
||||
runs-on:
|
||||
labels: ubuntu-latest
|
||||
steps:
|
||||
- name: Initialize environment
|
||||
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
./aio/node_modules
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@c83e99a12397014162531ca125c94549db55dd84
|
||||
- name: Install node modules for aio
|
||||
run: yarn install --cwd aio --frozen-lockfile
|
||||
- name: Set the stable branch environment variable
|
||||
id: latest_version
|
||||
run: |
|
||||
echo "CI_STABLE_BRANCH=$(npm info @angular/core dist-tags.latest | sed -r 's/^\s*([0-9]+\.[0-9]+)\.[0-9]+.*$/\1.x/')" >> $GITHUB_OUTPUT
|
||||
echo "CI_BRANCH=$(echo ${{ github.event.ref }} | cut -d '/' -f 3)" >> $GITHUB_OUTPUT
|
||||
- name: Deploy aio to production
|
||||
env:
|
||||
CI_AIO_MIN_PWA_SCORE: '95'
|
||||
CI_COMMIT: ${{ github.event.after }}
|
||||
CI_REPO_NAME: 'angular'
|
||||
CI_PULL_REQUEST: 'false'
|
||||
CI_REPO_OWNER: 'angular'
|
||||
CI_BUILD_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||
CI_STABLE_BRANCH: ${{ steps.latest_version.outputs.CI_STABLE_BRANCH }}
|
||||
CI_BRANCH: ${{ steps.latest_version.outputs.CI_BRANCH }}
|
||||
CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN: ${{ secrets.AIO_DEPLOY_TOKEN }}
|
||||
CI_SECRET_PAYLOAD_FIREBASE_TOKEN: ${{ secrets.AIO_PAYLOAD_TOKEN }}
|
||||
run: yarn --cwd aio deploy-production
|
||||
- name: Notify about failed deployment
|
||||
if: ${{ failure() }}
|
||||
uses: slackapi/slack-github-action@2a8087d4af6f83146a87539a70defe909fe6dbe6 # v=v1.24.0
|
||||
with:
|
||||
channel-id: 'C07DT5M6V,CKV1F72BG'
|
||||
slack-message: 'Deploy to aio job failed for ${{ github.base_ref }} branch failed on build ${{ github.event.after }}: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||
env:
|
||||
SLACK_BOT_TOKEN: ${{ secrets.ANGULAR_ROBOT_SLACK_TOKEN }}
|
||||
|
||||
publish-snapshots:
|
||||
if: github.event_name == 'push'
|
||||
runs-on:
|
||||
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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: echo "https://${{secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN}}:@github.com" > ${HOME}/.git_credentials
|
||||
@@ -127,7 +215,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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
with:
|
||||
cache-node-modules: true
|
||||
node-module-directories: |
|
||||
@@ -135,9 +223,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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Install node modules
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: |
|
||||
@@ -176,7 +264,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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
with:
|
||||
cache-node-modules: true
|
||||
# Checking out the pull request commit is intended here as we need to run the changed code tests.
|
||||
@@ -184,9 +272,9 @@ 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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Setup Bazel Remote Caching
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@50bb71e51d3372ca2e359adb9069f89beeac4ae7
|
||||
- name: Set up Sauce Tunnel Daemon
|
||||
@@ -204,13 +292,13 @@ jobs:
|
||||
SAUCE_TUNNEL_IDENTIFIER: angular-framework-${{ github.run_number }}
|
||||
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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
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
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Setup Saucelabs Variables
|
||||
uses: angular/dev-infra/github-actions/saucelabs@50bb71e51d3372ca2e359adb9069f89beeac4ae7
|
||||
- name: Starting Saucelabs tunnel service
|
||||
@@ -253,11 +341,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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Setup Bazel
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/setup@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- name: Setup Bazel RBE
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@5774b71c01a55c4c998f858ee37d3b77ae704c31
|
||||
uses: angular/dev-infra/github-actions/bazel/configure-remote@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
- 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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
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@4b433074a806bbbd4d319264430740cd46e62f27
|
||||
with:
|
||||
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
|
||||
|
||||
@@ -25,12 +25,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: 'Run analysis'
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
|
||||
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
|
||||
# Upload the results as artifacts.
|
||||
- name: 'Upload artifact'
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
@@ -47,6 +47,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: 'Upload to code-scanning'
|
||||
uses: github/codeql-action/upload-sarif@05963f47d870e2cb19a537396c1f668a348c7d8f # v3.24.8
|
||||
uses: github/codeql-action/upload-sarif@b7cec7526559c32f1616476ff32d17ba4c59b2d6 # v3.25.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# Update the `events.json` file that powers the [AIO events page](https://angular.io/events) (if
|
||||
# necessary) and create a pull request.
|
||||
#
|
||||
# For more details on the overall process, see
|
||||
# [aio/scripts/generate-events/README.md](../../aio/scripts/generate-events/README.md).
|
||||
|
||||
name: Update AIO events
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs: {}
|
||||
schedule:
|
||||
# Run every day at 15:00.
|
||||
- cron: '0 15 * * *'
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
update_events:
|
||||
name: Update `events.json` (if necessary)
|
||||
if: github.repository == 'angular/angular'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
# Setting `persist-credentials: false` prevents the github-action account from being the
|
||||
# account that is attempted to be used for authentication, instead the remote is set to
|
||||
# an authenticated URL.
|
||||
persist-credentials: false
|
||||
# This is needed as otherwise the PR creation will fail with `shallow update not allowed` when the forked branch is not in sync.
|
||||
fetch-depth: 0
|
||||
- name: Generate `events.json`
|
||||
run: node aio/scripts/generate-events/index.mjs --ignore-invalid-dates
|
||||
- name: Create a PR (if necessary)
|
||||
uses: angular/dev-infra/github-actions/create-pr-for-changes@c83e99a12397014162531ca125c94549db55dd84
|
||||
with:
|
||||
branch-prefix: docs-update-events
|
||||
pr-title: 'docs: update events'
|
||||
pr-description: |
|
||||
Generated `events.json` with the latest events retrieved from the Firebase DB.
|
||||
pr-labels: |
|
||||
action: review
|
||||
area: docs
|
||||
target: patch
|
||||
angular-robot-token: ${{ secrets.ANGULAR_ROBOT_ACCESS_TOKEN }}
|
||||
+84
-23
@@ -140,7 +140,7 @@ groups:
|
||||
- alxhub
|
||||
- crisbeto
|
||||
- ~jelbourn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
|
||||
# =========================================================
|
||||
# Framework: Compiler
|
||||
@@ -183,7 +183,7 @@ groups:
|
||||
- crisbeto
|
||||
- devversion
|
||||
- dylhunn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- AndrewKushnir
|
||||
|
||||
# =========================================================
|
||||
@@ -193,7 +193,7 @@ groups:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files.exclude("packages/core/schematics/*"), [
|
||||
contains_any_globs(files.exclude("packages/core/schematics/*").exclude('packages/core/primitives/*'), [
|
||||
'packages/core/**/{*,.*}',
|
||||
'packages/examples/core/**/{*,.*}',
|
||||
'packages/platform-browser/**/{*,.*}',
|
||||
@@ -358,7 +358,7 @@ groups:
|
||||
- crisbeto
|
||||
- devversion
|
||||
- dylhunn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -378,7 +378,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -415,7 +415,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -438,7 +438,7 @@ groups:
|
||||
- andrewseguin
|
||||
- atscott
|
||||
- dylhunn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -536,7 +536,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -615,7 +615,7 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- alxhub
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
|
||||
# =========================================================
|
||||
# Framework: Testing
|
||||
@@ -644,7 +644,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -663,7 +663,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -682,7 +682,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -778,7 +778,7 @@ groups:
|
||||
- atscott
|
||||
- crisbeto
|
||||
- dylhunn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- pkozlowski-opensource
|
||||
|
||||
# =========================================================
|
||||
@@ -813,7 +813,7 @@ groups:
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- dylhunn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- josephperrott
|
||||
- pkozlowski-opensource
|
||||
|
||||
@@ -867,7 +867,7 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- AndrewKushnir
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
|
||||
# =========================================================
|
||||
# Docs: Marketing
|
||||
@@ -946,7 +946,7 @@ groups:
|
||||
- alxhub
|
||||
- AndrewKushnir
|
||||
- atscott
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- jelbourn
|
||||
|
||||
# =========================================================
|
||||
@@ -1078,11 +1078,12 @@ groups:
|
||||
- josephperrott
|
||||
- jelbourn
|
||||
- bencodezen
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- dylhunn
|
||||
- AndrewKushnir
|
||||
- alxhub
|
||||
- crisbeto
|
||||
- devversion
|
||||
- atscott
|
||||
- pkozlowski-opensource
|
||||
- ~JeanMeche
|
||||
@@ -1143,7 +1144,7 @@ groups:
|
||||
reviewers:
|
||||
users:
|
||||
- AndrewKushnir
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- josephperrott
|
||||
|
||||
# =========================================================
|
||||
@@ -1200,7 +1201,7 @@ groups:
|
||||
'tools/gulp-tasks/**/{*,.*}',
|
||||
'tools/legacy-saucelabs/**/{*,.*}',
|
||||
'tools/manual_api_docs/**/{*,.*}',
|
||||
'tools/npm-patches/**/{*,.*}',
|
||||
'tools/npm-patches*/**/{*,.*}',
|
||||
'tools/rxjs/**/{*,.*}',
|
||||
'tools/saucelabs-daemon/**/{*,.*}',
|
||||
'tools/saucelabs/**/{*,.*}',
|
||||
@@ -1242,7 +1243,7 @@ groups:
|
||||
- atscott
|
||||
- dylhunn
|
||||
- ~jelbourn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- pkozlowski-opensource
|
||||
reviews:
|
||||
request: 3 # Request reviews from 3 people
|
||||
@@ -1268,7 +1269,7 @@ groups:
|
||||
- atscott
|
||||
- dylhunn
|
||||
- ~jelbourn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- pkozlowski-opensource
|
||||
reviews:
|
||||
request: 2 # Request reviews from 2 people
|
||||
@@ -1294,7 +1295,7 @@ groups:
|
||||
- atscott
|
||||
- dylhunn
|
||||
- ~jelbourn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- pkozlowski-opensource
|
||||
|
||||
####################################################################################
|
||||
@@ -1318,9 +1319,69 @@ groups:
|
||||
- andrewseguin
|
||||
- dgp1130
|
||||
- ~jelbourn
|
||||
- jessicajaniuk
|
||||
- thePunderWoman
|
||||
- josephperrott
|
||||
|
||||
# =========================================================
|
||||
# Primitives
|
||||
# =========================================================
|
||||
|
||||
# Angular team required reviews
|
||||
primitives:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'packages/core/primitives/**/{*,.*}',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- pkozlowski-opensource # Pawel Kozlowski
|
||||
- alxhub # Alex Rickabaugh
|
||||
- thePunderWoman # Jessica Janiuk
|
||||
- dylhunn # Dylan Hunn
|
||||
- AndrewKushnir # Andrew Kushnir
|
||||
- atscott # Andrew Scott
|
||||
reviews:
|
||||
required: 1
|
||||
reviewed_for: required
|
||||
labels:
|
||||
pending: 'requires: TGP'
|
||||
approved: 'requires: TGP'
|
||||
rejected: 'requires: TGP'
|
||||
|
||||
# External team required reviews
|
||||
primitives-shared:
|
||||
<<: *defaults
|
||||
conditions:
|
||||
- >
|
||||
contains_any_globs(files, [
|
||||
'packages/core/primitives/**/{*,.*}',
|
||||
])
|
||||
reviewers:
|
||||
users:
|
||||
- csmick # Cameron Smick
|
||||
- lannka # Hongfei Ding
|
||||
- eduhmc # Eduardo Huerta-Mercado
|
||||
- ehlemur # Edward Lesmes
|
||||
- ellenyuan # Ellen Yuan
|
||||
- jatraman # Jatin Ramanathan
|
||||
- jesse-good # Jesse Costello-Good
|
||||
- mturco # Matt Turco
|
||||
- neonstalwart # Ben Hockey
|
||||
- nicholasyu-google # Nicholas Yu
|
||||
- emspishak # Eric Spishak-Thomas
|
||||
- iteriani # Thomas Nguyen
|
||||
- tbondwilkinson # Tom Wilkinson
|
||||
- rahatarmanahmed # Rahat Ahmed
|
||||
reviews:
|
||||
required: 1
|
||||
reviewed_for: required
|
||||
labels:
|
||||
pending: 'requires: TGP'
|
||||
approved: 'requires: TGP'
|
||||
rejected: 'requires: TGP'
|
||||
|
||||
####################################################################################
|
||||
# Override managed result groups
|
||||
#
|
||||
|
||||
Vendored
+5
@@ -5,7 +5,12 @@
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"BazelBuild.vscode-bazel",
|
||||
"gkalpak.aio-docs-utils",
|
||||
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||
"xaver.clang-format",
|
||||
// The following extensions are useful when working on angular.io (i.e. inside the `aio/` directory).
|
||||
//"angular.ng-template",
|
||||
//"dbaeumer.vscode-eslint",
|
||||
//"errata-ai.vale-server",
|
||||
],
|
||||
}
|
||||
|
||||
+108
-104
@@ -1,49 +1,126 @@
|
||||
<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.
|
||||
<a name="17.3.12"></a>
|
||||
# 17.3.12 (2024-07-17)
|
||||
### 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)) |
|
||||
### compiler-cli
|
||||
| [327bae473b](https://github.com/angular/angular/commit/327bae473b4ed430efefb4663312a01f59304081) | fix | JIT mode incorrectly interpreting host directive configuration in partial compilation ([#57002](https://github.com/angular/angular/pull/57002)) ([#57003](https://github.com/angular/angular/pull/57003)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.11"></a>
|
||||
# 17.3.11 (2024-06-05)
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.10"></a>
|
||||
# 17.3.10 (2024-05-22)
|
||||
|
||||
This release includes some internal updates for Angular's documentation infrastructure.
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.9"></a>
|
||||
# 17.3.9 (2024-05-15)
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.8"></a>
|
||||
# 17.3.8 (2024-05-08)
|
||||
### compiler
|
||||
| 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)) |
|
||||
| [c21b459ba6](https://github.com/angular/angular/commit/c21b459ba6520fd5835e23800338ac9c997fee91) | fix | add math elements to schema ([#55631](https://github.com/angular/angular/pull/55631)) ([#55645](https://github.com/angular/angular/pull/55645)) |
|
||||
### 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
|
||||
| [3818436ebc](https://github.com/angular/angular/commit/3818436ebc649267bb39b976b6b567b7f2b06a64) | fix | don't schedule timer triggers on the server ([#55605](https://github.com/angular/angular/pull/55605)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.7"></a>
|
||||
# 17.3.7 (2024-05-01)
|
||||
### compiler-cli
|
||||
| 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
|
||||
| [51ac883167](https://github.com/angular/angular/commit/51ac8831670637b562dfa135bec1e27a0b49f21d) | fix | don't type check the bodies of control flow nodes in basic mode ([#55558](https://github.com/angular/angular/pull/55558)) |
|
||||
### core
|
||||
| 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)) |
|
||||
| [af0eb846a5](https://github.com/angular/angular/commit/af0eb846a572d0e9de2c6bb7016ddd339473dc00) | fix | render hooks should not specifically run outside the Angular zone ([#55399](https://github.com/angular/angular/pull/55399)) |
|
||||
### 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)) |
|
||||
| [3eea50da64](https://github.com/angular/angular/commit/3eea50da644f6023e7f001b8738c54cb89aece4c) | fix | Scroller should scroll as soon as change detection completes ([#55105](https://github.com/angular/angular/pull/55105)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.6"></a>
|
||||
# 17.3.6 (2024-04-25)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [826861b1fa](https://github.com/angular/angular/commit/826861b1fa7693010743f5dd881fb31ec33eee52) | fix | DeferBlockFixture.render should not wait for stability ([#55271](https://github.com/angular/angular/pull/55271)) |
|
||||
| [5cf14da35c](https://github.com/angular/angular/commit/5cf14da35cce1ea4456bae4365d3dbe6667b1881) | fix | make `ActivatedRoute` inject correct instance inside `@defer` blocks ([#55374](https://github.com/angular/angular/pull/55374)) |
|
||||
| [8979fba2c5](https://github.com/angular/angular/commit/8979fba2c5813673767a133caeec9ac768d17329) | fix | skip defer timers on the server ([#55480](https://github.com/angular/angular/pull/55480)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.5"></a>
|
||||
# 17.3.5 (2024-04-17)
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.4"></a>
|
||||
# 17.3.4 (2024-04-10)
|
||||
### common
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [53427d875d](https://github.com/angular/angular/commit/53427d875d33de16b1dbb04e76a9fe32a2b8a445) | fix | invalid ImageKit quality parameter ([#55193](https://github.com/angular/angular/pull/55193)) |
|
||||
| [766548c3ec](https://github.com/angular/angular/commit/766548c3ecc06ffd8f06ed9a7d0cbb3db6f1b0f6) | fix | skip transfer cache on client ([#55012](https://github.com/angular/angular/pull/55012)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.3"></a>
|
||||
# 17.3.3 (2024-04-03)
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [158ceaf062](https://github.com/angular/angular/commit/158ceaf062036bde2a828ee769580f99433a31a8) | fix | handle `ChainedInjector`s in injector debug utils ([#55144](https://github.com/angular/angular/pull/55144)) |
|
||||
| [4d043992e5](https://github.com/angular/angular/commit/4d043992e5635a2f841b633fb38d0009a39f05d0) | fix | test cleanup should not throw if Zone is not present ([#55096](https://github.com/angular/angular/pull/55096)) |
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [949dec26b8](https://github.com/angular/angular/commit/949dec26b860a500e90874ad778da74549d21d7e) | fix | avoid conflicts with some greek letters in control flow migration ([#55113](https://github.com/angular/angular/pull/55113)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
<a name="17.3.2"></a>
|
||||
# 17.3.2 (2024-03-28)
|
||||
### compiler
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [2b7bad5151](https://github.com/angular/angular/commit/2b7bad515100cbfa40b3e8d844bae13d43fd5602) | fix | invoke method-based tracking function with context ([#54960](https://github.com/angular/angular/pull/54960)) |
|
||||
### compiler-cli
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [b478dfbfda](https://github.com/angular/angular/commit/b478dfbfda3f32fbe723a1e8725e86490422520d) | fix | report errors when initializer APIs are used on private fields ([#55070](https://github.com/angular/angular/pull/55070)) |
|
||||
### core
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [708ba8115f](https://github.com/angular/angular/commit/708ba8115f7ad05201db5c529aefe4dd48fc64c5) | fix | establish proper injector resolution order for `@defer` blocks ([#55079](https://github.com/angular/angular/pull/55079)) |
|
||||
### http
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [cb433af0e1](https://github.com/angular/angular/commit/cb433af0e1ba61073eb4a02ccd75cf360e9fd409) | fix | include transferCache when cloning HttpRequest ([#54939](https://github.com/angular/angular/pull/54939)) |
|
||||
| [64f202cab9](https://github.com/angular/angular/commit/64f202cab9e7a5c873b17bbddd02368006426152) | fix | manage different body types for caching POST requests ([#54980](https://github.com/angular/angular/pull/54980)) |
|
||||
### migrations
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [2f9d94bc4a](https://github.com/angular/angular/commit/2f9d94bc4ab5a94e620a13404aba4e094f8b2344) | fix | account for variables in imports initializer ([#55081](https://github.com/angular/angular/pull/55081)) |
|
||||
### router
|
||||
| Commit | Type | Description |
|
||||
| -- | -- | -- |
|
||||
| [365fd50407](https://github.com/angular/angular/commit/365fd504077d0e7509efc3077ea4ae8bbafb01f7) | fix | RouterLinkActive will always remove active classes when links are not active ([#54982](https://github.com/angular/angular/pull/54982)) |
|
||||
|
||||
<!-- CHANGELOG SPLIT MARKER -->
|
||||
|
||||
@@ -60,79 +137,6 @@
|
||||
|
||||
<!-- 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
|
||||
|
||||
@@ -389,7 +389,6 @@ The following documents can help you sort out issues with GitHub accounts and mu
|
||||
|
||||
|
||||
|
||||
[angular-group]: https://groups.google.com/forum/#!forum/angular
|
||||
[coc]: https://github.com/angular/code-of-conduct/blob/main/CODE_OF_CONDUCT.md
|
||||
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
|
||||
[corporate-cla]: https://cla.developers.google.com/about/google-corporate
|
||||
@@ -398,7 +397,3 @@ The following documents can help you sort out issues with GitHub accounts and mu
|
||||
[discord]: https://discord.gg/angular
|
||||
[individual-cla]: https://cla.developers.google.com/about/google-individual
|
||||
[js-style-guide]: https://google.github.io/styleguide/jsguide.html
|
||||
[jsfiddle]: https://jsfiddle.net/
|
||||
[plunker]: https://plnkr.co/edit
|
||||
[runnable]: https://runnable.com/
|
||||
[stackoverflow]: https://stackoverflow.com/questions/tagged/angular
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<h1 align="center">Angular - The modern web developer's platform</h1>
|
||||
|
||||
<p align="center">
|
||||
<img src="aio/src/assets/images/logos/angular/angular_renaissance.png" alt="angular-logo" width="120px" height="120px"/>
|
||||
<img src="adev/src/assets/images/press-kit/angular_icon_gradient.gif" alt="angular-logo" width="120px" height="120px"/>
|
||||
<br>
|
||||
<em>Angular is a development platform for building mobile and desktop web applications
|
||||
<br> using TypeScript/JavaScript and other languages.</em>
|
||||
@@ -167,8 +167,8 @@ Join the conversation and help the community.
|
||||
[angularmaterial]: https://material.angular.io/
|
||||
[cli]: https://angular.dev/tools/cli
|
||||
[architecture]: https://angular.dev/essentials
|
||||
[componentstemplates]: https://angular.dev/tutorials/learn-angular/components-in-angular
|
||||
[forms]: https://angular.dev/tutorials/learn-angular/forms
|
||||
[componentstemplates]: https://angular.dev/tutorials/learn-angular/1-components-in-angular
|
||||
[forms]: https://angular.dev/tutorials/learn-angular/15-forms
|
||||
[api]: https://angular.dev/api
|
||||
[angularelements]: https://angular.dev/guide/elements
|
||||
[ssr]: https://angular.dev/guide/ssr
|
||||
|
||||
@@ -9,20 +9,6 @@ workspace(
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
load("//:yarn.bzl", "YARN_LABEL")
|
||||
|
||||
# Add a patch fix for rules_webtesting v0.3.5 required for enabling runfiles on Windows.
|
||||
# TODO: Remove the http_archive for this transitive dependency when a release is cut
|
||||
# for https://github.com/bazelbuild/rules_webtesting/commit/581b1557e382f93419da6a03b91a45c2ac9a9ec8
|
||||
# and the version is updated in rules_nodejs.
|
||||
http_archive(
|
||||
name = "io_bazel_rules_webtesting",
|
||||
patch_args = ["-p1"],
|
||||
patches = [
|
||||
"//:tools/bazel-repo-patches/rules_webtesting__windows_runfiles_fix.patch",
|
||||
],
|
||||
sha256 = "e9abb7658b6a129740c0b3ef6f5a2370864e102a5ba5ffca2cea565829ed825a",
|
||||
urls = ["https://github.com/bazelbuild/rules_webtesting/releases/download/0.3.5/rules_webtesting.tar.gz"],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "build_bazel_rules_nodejs",
|
||||
patches = [
|
||||
@@ -65,16 +51,16 @@ load("@rules_nodejs//nodejs:repositories.bzl", "nodejs_register_toolchains")
|
||||
nodejs_register_toolchains(
|
||||
name = "nodejs",
|
||||
node_repositories = {
|
||||
"18.18.2-darwin_arm64": ("node-v18.18.2-darwin-arm64.tar.gz", "node-v18.18.2-darwin-arm64", "9f982cc91b28778dd8638e4f94563b0c2a1da7aba62beb72bd427721035ab553"),
|
||||
"18.18.2-darwin_amd64": ("node-v18.18.2-darwin-x64.tar.gz", "node-v18.18.2-darwin-x64", "5bb8da908ed590e256a69bf2862238c8a67bc4600119f2f7721ca18a7c810c0f"),
|
||||
"18.18.2-linux_arm64": ("node-v18.18.2-linux-arm64.tar.xz", "node-v18.18.2-linux-arm64", "2e630e18548627f61eaf573233da7949dc0a1df5eef3f486fa9820c5f6c121aa"),
|
||||
"18.18.2-linux_ppc64le": ("node-v18.18.2-linux-ppc64le.tar.xz", "node-v18.18.2-linux-ppc64le", "b0adff5cf5938266b711d6c724fb134d802e0dee40b3a3f73d162de1b3d11880"),
|
||||
"18.18.2-linux_s390x": ("node-v18.18.2-linux-s390x.tar.xz", "node-v18.18.2-linux-s390x", "c70ec2074b5e2b42c55bb4b8105418b67bf8a61c500d9376a07430dfcc341fdb"),
|
||||
"18.18.2-linux_amd64": ("node-v18.18.2-linux-x64.tar.xz", "node-v18.18.2-linux-x64", "75aba25ae76999309fc6c598efe56ce53fbfc221381a44a840864276264ab8ac"),
|
||||
"18.18.2-windows_amd64": ("node-v18.18.2-win-x64.zip", "node-v18.18.2-win-x64", "3bb0e51e579a41a22b3bf6cb2f3e79c03801aa17acbe0ca00fc555d1282e7acd"),
|
||||
"18.19.1-darwin_arm64": ("node-v18.19.1-darwin-arm64.tar.gz", "node-v18.19.1-darwin-arm64", "0c7249318868877032ed21cc0ed450015ee44b31b9b281955521cd3fc39fbfa3"),
|
||||
"18.19.1-darwin_amd64": ("node-v18.19.1-darwin-x64.tar.gz", "node-v18.19.1-darwin-x64", "ab67c52c0d215d6890197c951e1bd479b6140ab630212b96867395e21d813016"),
|
||||
"18.19.1-linux_arm64": ("node-v18.19.1-linux-arm64.tar.xz", "node-v18.19.1-linux-arm64", "228ad1eee660fba3f9fd2cccf02f05b8ebccc294d27f22c155d20b233a9d76b3"),
|
||||
"18.19.1-linux_ppc64le": ("node-v18.19.1-linux-ppc64le.tar.xz", "node-v18.19.1-linux-ppc64le", "2e5812b8fc00548e2e8ab9daa88ace13974c16b6ba5595a7a50c35f848f7d432"),
|
||||
"18.19.1-linux_s390x": ("node-v18.19.1-linux-s390x.tar.xz", "node-v18.19.1-linux-s390x", "15106acf4c9e3aca02416dd89fb5c71af77097042455a73f9caa064c1988ead5"),
|
||||
"18.19.1-linux_amd64": ("node-v18.19.1-linux-x64.tar.xz", "node-v18.19.1-linux-x64", "f35f24edd4415cd609a2ebc03be03ed2cfe211d7333d55c752d831754fb849f0"),
|
||||
"18.19.1-windows_amd64": ("node-v18.19.1-win-x64.zip", "node-v18.19.1-win-x64", "ff08f8fe253fba9274992d7052e9d9a70141342d7b36ddbd6e84cbe823e312c6"),
|
||||
},
|
||||
# We need at least Node 18.17 due to some transitive dependencies.
|
||||
node_version = "18.18.2",
|
||||
node_version = "18.19.1",
|
||||
)
|
||||
|
||||
# Download npm dependencies.
|
||||
@@ -206,10 +192,10 @@ cldr_xml_data_repository(
|
||||
# sass rules
|
||||
http_archive(
|
||||
name = "io_bazel_rules_sass",
|
||||
sha256 = "5633816e996a79c77f44306f6228b9ef18fc2ecb412d63b4e314a132225facba",
|
||||
strip_prefix = "rules_sass-79bd239ce77c101ea1aed575678020bd2999f17d",
|
||||
sha256 = "e50e1ca1b0a737d2c09efbbb886e0194d99caed617337a766b17c1ee4bae93f2",
|
||||
strip_prefix = "rules_sass-fcce06104e072bbebbf92c1a244ea9f8c2fc8402",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/rules_sass/archive/79bd239ce77c101ea1aed575678020bd2999f17d.zip",
|
||||
"https://github.com/bazelbuild/rules_sass/archive/fcce06104e072bbebbf92c1a244ea9f8c2fc8402.zip",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
+29
-18
@@ -1,8 +1,9 @@
|
||||
load("//:packages.bzl", "link_packages")
|
||||
load("@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")
|
||||
load("@bazel_skylib//lib:collections.bzl", "collections")
|
||||
load("//adev/tools/local_deps:index.bzl", "ensure_local_package_deps", "link_local_packages")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
@@ -30,7 +31,17 @@ TEST_FILES = APPLICATION_FILES + [
|
||||
["**/*.spec.ts"],
|
||||
)
|
||||
|
||||
APPLICATION_DEPS = link_packages([
|
||||
APPLICATION_ASSETS = [
|
||||
"//adev/src/assets/images",
|
||||
"//adev/src/assets/textures",
|
||||
"//adev/src/assets/previews",
|
||||
"//adev/src/assets:tutorials",
|
||||
"//adev/src/assets/icons",
|
||||
"//adev/src/assets:api",
|
||||
"//adev/src/assets:content",
|
||||
]
|
||||
|
||||
APPLICATION_DEPS = [
|
||||
"@npm//@angular-devkit/build-angular",
|
||||
"@npm//@angular/animations",
|
||||
"@npm//@angular/cdk",
|
||||
@@ -50,13 +61,6 @@ APPLICATION_DEPS = link_packages([
|
||||
"@npm//ogl",
|
||||
"@npm//rxjs",
|
||||
"@npm//typescript",
|
||||
"//adev/src/assets/images",
|
||||
"//adev/src/assets/textures",
|
||||
"//adev/src/assets/previews",
|
||||
"//adev/src/assets:tutorials",
|
||||
"//adev/src/assets/icons",
|
||||
"//adev/src/assets:api",
|
||||
"//adev/src/assets:content",
|
||||
"@npm//@typescript/vfs",
|
||||
"@npm//@codemirror/state",
|
||||
"@npm//@codemirror/view",
|
||||
@@ -73,14 +77,13 @@ 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",
|
||||
])
|
||||
]
|
||||
|
||||
TEST_DEPS = APPLICATION_DEPS + link_packages([
|
||||
TEST_DEPS = APPLICATION_DEPS + [
|
||||
"@npm//@angular/platform-browser-dynamic",
|
||||
"@npm//@angular/build-tooling/bazel/browsers/chromium",
|
||||
"@npm//@types/jasmine",
|
||||
"@npm//@types/node",
|
||||
"@npm//assert",
|
||||
@@ -90,8 +93,13 @@ TEST_DEPS = APPLICATION_DEPS + link_packages([
|
||||
"@npm//karma-coverage",
|
||||
"@npm//karma-jasmine",
|
||||
"@npm//karma-jasmine-html-reporter",
|
||||
"//aio/tools:windows-chromium-path",
|
||||
])
|
||||
]
|
||||
|
||||
# Create `npm_link` targets for all dependencies that correspond to a
|
||||
# first-party Angular package that can be built from `HEAD`.
|
||||
link_local_packages(
|
||||
all_deps = collections.uniq(APPLICATION_DEPS + TEST_DEPS),
|
||||
)
|
||||
|
||||
copy_to_bin(
|
||||
name = "application_files_bin",
|
||||
@@ -129,7 +137,7 @@ architect(
|
||||
"--output-path=build",
|
||||
] + config_based_architect_flags,
|
||||
chdir = "$(RULEDIR)",
|
||||
data = APPLICATION_DEPS + [
|
||||
data = ensure_local_package_deps(APPLICATION_DEPS) + APPLICATION_ASSETS + [
|
||||
":application_files_bin",
|
||||
],
|
||||
# Network is required to inline fonts.
|
||||
@@ -149,7 +157,7 @@ architect(
|
||||
"--watch",
|
||||
],
|
||||
chdir = package_name(),
|
||||
data = APPLICATION_DEPS + [
|
||||
data = ensure_local_package_deps(APPLICATION_DEPS) + APPLICATION_ASSETS + [
|
||||
":application_files_bin",
|
||||
],
|
||||
tags = [
|
||||
@@ -164,7 +172,10 @@ architect_test(
|
||||
"--no-watch",
|
||||
],
|
||||
chdir = package_name(),
|
||||
data = TEST_DEPS + TEST_FILES,
|
||||
data = ensure_local_package_deps(TEST_DEPS) + TEST_FILES + APPLICATION_ASSETS + [
|
||||
"//aio/tools:windows-chromium-path",
|
||||
"@npm//@angular/build-tooling/bazel/browsers/chromium",
|
||||
],
|
||||
env = {
|
||||
"CHROME_BIN": "../$(CHROMIUM)",
|
||||
},
|
||||
|
||||
+8
-9
@@ -19,9 +19,7 @@
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:application",
|
||||
"options": {
|
||||
"externalDependencies": [
|
||||
"path"
|
||||
],
|
||||
"externalDependencies": ["path"],
|
||||
"outputPath": "dist/angular-dev",
|
||||
"index": "src/index.html",
|
||||
"browser": "src/main.ts",
|
||||
@@ -29,11 +27,7 @@
|
||||
"polyfills": ["src/polyfills.ts", "zone.js"],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/robots.txt",
|
||||
"src/assets"
|
||||
],
|
||||
"assets": ["src/favicon.ico", "src/robots.txt", "src/assets"],
|
||||
"styles": ["@angular/docs/styles/global-styles.scss"],
|
||||
"scripts": [],
|
||||
"webWorkerTsConfig": "tsconfig.worker.json",
|
||||
@@ -99,6 +93,11 @@
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": "dca119a9-da31-47f7-a6cb-b60541037021"
|
||||
"analytics": "dca119a9-da31-47f7-a6cb-b60541037021",
|
||||
"cache": {
|
||||
// Disable build caching as the cache folder will just be dropped
|
||||
// when run under Bazel sandboxed execution.
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
export const VERSIONS_CONFIG = {
|
||||
currentVersion: 'stable',
|
||||
historicalVersionsLinkPattern: 'https://v{{version}}.angular.dev',
|
||||
mainVersions: [
|
||||
{
|
||||
version: 'stable',
|
||||
url: 'https://angular.dev',
|
||||
},
|
||||
{
|
||||
version: 'v16',
|
||||
url: 'https://v16.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v15',
|
||||
url: 'https://v15.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v14',
|
||||
url: 'https://v14.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v13',
|
||||
url: 'https://v13.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v12',
|
||||
url: 'https://v12.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v11',
|
||||
url: 'https://v11.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v10',
|
||||
url: 'https://v10.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v9',
|
||||
url: 'https://v9.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v8',
|
||||
url: 'https://v8.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v7',
|
||||
url: 'https://v7.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v6',
|
||||
url: 'https://v6.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v5',
|
||||
url: 'https://v5.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v4',
|
||||
url: 'https://v4.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v2',
|
||||
url: 'https://v2.angular.io/docs',
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
<div [attr.id]="SECONDARY_NAV_ID" class="adev-secondary-nav-mask" [class.docs-nav-secondary--open]="isSecondaryNavVisible()" (docsClickOutside)="close()" [docsClickOutsideIgnore]="[PRIMARY_NAV_ID]">
|
||||
<div class="docs-nav-secondary docs-scroll-track-transparent" [style.transform]="translateX()" [style.transition]="transition">
|
||||
<div class="docs-nav-secondary docs-scroll-track-transparent" [style.transform]="translateX()" [style.transition]="transition()">
|
||||
<!-- Secondary Nav -->
|
||||
@if (navigationItems && navigationItems.length > 0) {
|
||||
<docs-navigation-list
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
PLATFORM_ID,
|
||||
computed,
|
||||
inject,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import {takeUntilDestroyed, toObservable} from '@angular/core/rxjs-interop';
|
||||
import {
|
||||
@@ -76,7 +77,7 @@ export class SecondaryNavigation implements OnInit {
|
||||
const level = this.navigationState.expandedItems()?.length ?? 0;
|
||||
return `translateX(${-level * 100}%)`;
|
||||
});
|
||||
transition: string = '0ms';
|
||||
transition = signal('0ms');
|
||||
|
||||
readonly PRIMARY_NAV_ID = PRIMARY_NAV_ID;
|
||||
readonly SECONDARY_NAV_ID = SECONDARY_NAV_ID;
|
||||
@@ -182,7 +183,7 @@ export class SecondaryNavigation implements OnInit {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.transition = `${ANIMATION_DURATION}ms`;
|
||||
this.transition.set(`${ANIMATION_DURATION}ms`);
|
||||
}, ANIMATION_DURATION);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {HttpClient} from '@angular/common/http';
|
||||
import {Injectable, inject} from '@angular/core';
|
||||
import {DocContent, DocsContentLoader} from '@angular/docs';
|
||||
import {Router} from '@angular/router';
|
||||
import {firstValueFrom} from 'rxjs';
|
||||
import {map} from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
@@ -27,12 +28,13 @@ export class ContentLoader implements DocsContentLoader {
|
||||
try {
|
||||
this.cache.set(
|
||||
path,
|
||||
this.httpClient
|
||||
.get(`assets/content/${path}`, {
|
||||
responseType: 'text',
|
||||
})
|
||||
.pipe(map((contents) => ({contents, id: path})))
|
||||
.toPromise(),
|
||||
firstValueFrom(
|
||||
this.httpClient
|
||||
.get(`assets/content/${path}`, {
|
||||
responseType: 'text',
|
||||
})
|
||||
.pipe(map((contents) => ({contents, id: path}))),
|
||||
),
|
||||
);
|
||||
} catch {
|
||||
this.router.navigateByUrl('/404');
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, Inject} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, Inject} from '@angular/core';
|
||||
import {MAT_SNACK_BAR_DATA, MatSnackBarAction, MatSnackBarRef} from '@angular/material/snack-bar';
|
||||
|
||||
export interface ErrorSnackBarData {
|
||||
@@ -16,6 +16,7 @@ export interface ErrorSnackBarData {
|
||||
|
||||
@Component({
|
||||
selector: 'error-snack-bar',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: `
|
||||
{{ message }}
|
||||
<button
|
||||
@@ -28,8 +29,8 @@ export interface ErrorSnackBarData {
|
||||
{{ actionText }}
|
||||
</button>
|
||||
`,
|
||||
imports: [MatSnackBarAction],
|
||||
standalone: true,
|
||||
imports: [MatSnackBarAction],
|
||||
styles: `:host { display: flex; align-items: center; button { margin-left: 16px }}`,
|
||||
})
|
||||
export class ErrorSnackBar {
|
||||
|
||||
@@ -82,7 +82,7 @@ export class ThemeManager {
|
||||
}
|
||||
|
||||
private watchPreferredColorScheme() {
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (event) => {
|
||||
window.matchMedia(PREFERS_COLOR_SCHEME_DARK).addEventListener('change', (event) => {
|
||||
const preferredScheme = event.matches ? 'dark' : 'light';
|
||||
this.setThemeBodyClasses(preferredScheme);
|
||||
});
|
||||
@@ -90,5 +90,5 @@ export class ThemeManager {
|
||||
}
|
||||
|
||||
function preferredScheme(): 'dark' | 'light' {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
return window.matchMedia(PREFERS_COLOR_SCHEME_DARK).matches ? 'dark' : 'light';
|
||||
}
|
||||
|
||||
@@ -7,74 +7,7 @@
|
||||
*/
|
||||
|
||||
import {Injectable, VERSION, computed, signal} from '@angular/core';
|
||||
|
||||
// TODO(josephperrott): extract this out of the file into a managed location.
|
||||
const VERSIONS_CONFIG = {
|
||||
currentVersion: 'stable',
|
||||
historicalVersionsLinkPattern: 'https://v{{version}}.angular.dev',
|
||||
mainVersions: [
|
||||
{
|
||||
version: 'stable',
|
||||
url: 'https://angular.dev',
|
||||
},
|
||||
{
|
||||
version: 'v16',
|
||||
url: 'https://v16.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v15',
|
||||
url: 'https://v15.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v14',
|
||||
url: 'https://v14.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v13',
|
||||
url: 'https://v13.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v12',
|
||||
url: 'https://v12.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v11',
|
||||
url: 'https://v11.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v10',
|
||||
url: 'https://v10.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v9',
|
||||
url: 'https://v9.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v8',
|
||||
url: 'https://v8.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v7',
|
||||
url: 'https://v7.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v6',
|
||||
url: 'https://v6.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v5',
|
||||
url: 'https://v5.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v4',
|
||||
url: 'https://v4.angular.io/docs',
|
||||
},
|
||||
{
|
||||
version: 'v2',
|
||||
url: 'https://v2.angular.io/docs',
|
||||
},
|
||||
],
|
||||
};
|
||||
import {VERSIONS_CONFIG} from '../constants/versions';
|
||||
|
||||
export interface Version {
|
||||
displayName: string;
|
||||
|
||||
@@ -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,6 +8,7 @@ $width-breakpoint: 950px;
|
||||
container-name: embedded-editor;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
border: 1px solid var(--senary-contrast);
|
||||
}
|
||||
|
||||
// The entire thing - editor, terminal, console
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -8,13 +8,14 @@
|
||||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {DocContent, DocViewer} from '@angular/docs';
|
||||
import {Component, inject} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, inject} from '@angular/core';
|
||||
import {toSignal} from '@angular/core/rxjs-interop';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import {map} from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'docs-docs',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [CommonModule, DocViewer],
|
||||
styleUrls: ['./docs.component.scss'],
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -36,6 +36,7 @@
|
||||
box-sizing: border-box;
|
||||
transition: background 0.3s ease, border 0.3s ease;
|
||||
|
||||
h1,
|
||||
p {
|
||||
display: inline;
|
||||
font-size: 0.875rem;
|
||||
|
||||
+21
-2
@@ -108,7 +108,6 @@
|
||||
& > .docs-code {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
max-height: 93vh;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
|
||||
@@ -119,6 +118,7 @@
|
||||
|
||||
button {
|
||||
transition: background-color 0.3s ease;
|
||||
font-family: monospace;
|
||||
|
||||
&.hljs-ln-line {
|
||||
font-weight: 400;
|
||||
@@ -154,6 +154,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.docs-reference-cli-toc {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.adev-reference-tab {
|
||||
min-width: 50ch;
|
||||
margin-block-start: 2.5rem;
|
||||
@@ -267,7 +271,9 @@
|
||||
background-color: var(--octonary-contrast);
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
transition: background-color 0.3s ease, border 0.3s ease;
|
||||
transition:
|
||||
background-color 0.3s ease,
|
||||
border 0.3s ease;
|
||||
|
||||
// h3 + code || # of overloads
|
||||
.docs-reference-header {
|
||||
@@ -404,4 +410,17 @@
|
||||
margin-block-start: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.docs-ref-content {
|
||||
padding: 1rem 0;
|
||||
|
||||
&:not(:first-child) {
|
||||
border-block-start: 1px solid var(--senary-contrast);
|
||||
}
|
||||
|
||||
.docs-param-keyword {
|
||||
display: block;
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+25
-4
@@ -16,12 +16,12 @@ import {
|
||||
inject,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import {DOCUMENT, NgFor, NgIf} from '@angular/common';
|
||||
import {DOCUMENT, NgFor, NgIf, ViewportScroller} from '@angular/common';
|
||||
import {MatTabGroup, MatTabsModule} from '@angular/material/tabs';
|
||||
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
||||
import {distinctUntilChanged, map} from 'rxjs/operators';
|
||||
import {takeUntilDestroyed, toSignal} from '@angular/core/rxjs-interop';
|
||||
import {distinctUntilChanged, filter, map, take} from 'rxjs/operators';
|
||||
import {DocContent, DocViewer} from '@angular/docs';
|
||||
import {ActivatedRoute, Router, RouterLink} from '@angular/router';
|
||||
import {ActivatedRoute, Router, RouterLink, Scroll} from '@angular/router';
|
||||
import {ApiItemType} from './../interfaces/api-item-type';
|
||||
import {ReferenceScrollHandler} from '../services/reference-scroll-handler.service';
|
||||
import {
|
||||
@@ -51,6 +51,15 @@ export default class ApiReferenceDetailsPage implements OnInit, AfterViewInit {
|
||||
private readonly document = inject(DOCUMENT);
|
||||
private readonly router = inject(Router);
|
||||
private readonly scrollHandler = inject(ReferenceScrollHandler);
|
||||
private readonly scroller = inject(ViewportScroller);
|
||||
private scrollEvent = toSignal(
|
||||
this.router.events.pipe(
|
||||
filter((e): e is Scroll => e instanceof Scroll),
|
||||
take(1),
|
||||
),
|
||||
{initialValue: null},
|
||||
);
|
||||
private cardsDisplayedOnInit = false;
|
||||
|
||||
ApiItemType = ApiItemType;
|
||||
|
||||
@@ -67,10 +76,22 @@ export default class ApiReferenceDetailsPage implements OnInit, AfterViewInit {
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.setActiveTab();
|
||||
if (this.canDisplayCards()) {
|
||||
this.cardsDisplayedOnInit = true;
|
||||
}
|
||||
this.listenToTabChange();
|
||||
}
|
||||
|
||||
membersCardsLoaded(): void {
|
||||
const event = this.scrollEvent();
|
||||
if (this.cardsDisplayedOnInit && event) {
|
||||
// Cards loaded after scroll event happened. We have to handle the scroll event manually
|
||||
if (event.position) {
|
||||
this.scroller.scrollToPosition(event.position);
|
||||
} else if (event.anchor) {
|
||||
this.scroller.scrollToAnchor(event.anchor);
|
||||
}
|
||||
}
|
||||
this.scrollHandler.setupListeners(API_TAB_CLASS_NAME);
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -3,6 +3,11 @@
|
||||
<h6>Getting Started</h6>
|
||||
<h1 tabindex="-1">API Reference</h1>
|
||||
</header>
|
||||
|
||||
@if (featuredGroup().items.length) {
|
||||
<adev-api-items-section [group]="featuredGroup()" class="adev-featured-list" />
|
||||
}
|
||||
|
||||
<form class="adev-reference-list-form">
|
||||
<docs-text-field
|
||||
name="query"
|
||||
@@ -34,12 +39,8 @@
|
||||
</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" />
|
||||
}
|
||||
|
||||
<span id="deprecated-description" class="docs-deprecated-description">Deprecated</span>
|
||||
</div>
|
||||
|
||||
+5
-9
@@ -77,8 +77,9 @@
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap-reverse;
|
||||
gap: 1.5rem;
|
||||
padding-block-start: 0;
|
||||
padding-block-start: 1.5rem;
|
||||
padding-block-end: 2rem;
|
||||
border-block: 1px solid var(--senary-contrast);
|
||||
}
|
||||
|
||||
.adev-reference-list-form-part-two {
|
||||
@@ -89,15 +90,10 @@
|
||||
|
||||
.adev-featured-list {
|
||||
display: block;
|
||||
padding-block-end: 2rem;
|
||||
padding-block-start: 1.5rem;
|
||||
padding-block-end: 1rem;
|
||||
margin-block: 1rem;
|
||||
border-block: 1px solid var(--senary-contrast);
|
||||
}
|
||||
|
||||
|
||||
.docs-deprecated-description {
|
||||
display: none;
|
||||
border-top: 0;
|
||||
margin-top: -1.5rem;
|
||||
}
|
||||
|
||||
.docs-api-item-label-full {
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import {ApiItemsGroup} from '../interfaces/api-items-group';
|
||||
import {ApiManifest} from '../interfaces/api-manifest';
|
||||
|
||||
export const FEATURED_API_ITEMS_KEY = 'apiFeaturedItems';
|
||||
export const FEATURED_GROUP_TITLE = 'Featured';
|
||||
export const FEATURED_GROUP_TITLE = 'Most Common';
|
||||
|
||||
export type FeaturedItemsByGroup = Record<string, ApiItem[]>;
|
||||
|
||||
|
||||
@@ -160,9 +160,6 @@ export class ReferenceScrollHandler implements OnDestroy, ReferenceScrollHandler
|
||||
for (const line of Array.from(activeLines)) {
|
||||
line.classList.remove(API_TAB_ACTIVE_CODE_LINE);
|
||||
}
|
||||
this.getAllMemberCards().forEach((card) => {
|
||||
card.blur();
|
||||
});
|
||||
} else {
|
||||
const lines = this.document.querySelectorAll<HTMLButtonElement>(
|
||||
`button[${MEMBER_ID_ATTRIBUTE}="${currentActiveMemberId}"]`,
|
||||
@@ -170,7 +167,7 @@ export class ReferenceScrollHandler implements OnDestroy, ReferenceScrollHandler
|
||||
for (const line of Array.from(lines)) {
|
||||
line.classList.add(API_TAB_ACTIVE_CODE_LINE);
|
||||
}
|
||||
this.document.getElementById(`${currentActiveMemberId}`)?.focus();
|
||||
this.document.getElementById(`${currentActiveMemberId}`)?.focus({preventScroll: true});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +176,9 @@ export class ReferenceScrollHandler implements OnDestroy, ReferenceScrollHandler
|
||||
return;
|
||||
}
|
||||
|
||||
card.focus();
|
||||
if (card !== <HTMLElement>document.activeElement) {
|
||||
(<HTMLElement>document.activeElement).blur();
|
||||
}
|
||||
|
||||
this.window.scrollTo({
|
||||
top: card!.offsetTop - this.membersMarginTopInPx(),
|
||||
@@ -211,8 +210,9 @@ export class ReferenceScrollHandler implements OnDestroy, ReferenceScrollHandler
|
||||
|
||||
this.resizeObserver = new ResizeObserver((_) => {
|
||||
this.ngZone.run(() => {
|
||||
if (tabBody.offsetTop) {
|
||||
this.membersMarginTopInPx.set(tabBody.offsetTop);
|
||||
const offsetTop = tabBody.getBoundingClientRect().top;
|
||||
if (offsetTop) {
|
||||
this.membersMarginTopInPx.set(offsetTop);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -117,6 +117,11 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
path: 'guide/components/outputs',
|
||||
contentPath: 'guide/components/outputs',
|
||||
},
|
||||
{
|
||||
label: 'output() function',
|
||||
path: 'guide/components/output-fn',
|
||||
contentPath: 'guide/components/output-function',
|
||||
},
|
||||
{
|
||||
label: 'Content projection with ng-content',
|
||||
path: 'guide/components/content-projection',
|
||||
@@ -1143,9 +1148,9 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [
|
||||
contentPath: 'reference/errors/NG3003',
|
||||
},
|
||||
{
|
||||
label: 'NG5000: Hydration with unsupported Zone.js instance.',
|
||||
path: 'errors/NG5000',
|
||||
contentPath: 'reference/errors/NG5000',
|
||||
label: 'NG05000: Hydration with unsupported Zone.js instance.',
|
||||
path: 'errors/NG05000',
|
||||
contentPath: 'reference/errors/NG05000',
|
||||
},
|
||||
{
|
||||
label: 'NG6100: NgModule.id Set to module.id anti-pattern',
|
||||
|
||||
|
Before Width: | Height: | Size: 3.4 MiB After Width: | Height: | Size: 3.4 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
@@ -59,8 +59,6 @@ If Angular handles an event within a component with OnPush strategy, the framewo
|
||||
|
||||
As an example, if Angular handles an event within `MainComponent`, the framework will run change detection in the entire component tree. Angular will ignore the subtree with root `LoginComponent` because it has `OnPush` and the event happened outside of its scope.
|
||||
|
||||
<img alt="Change detection propagation from OnPush component" src="assets/images/best-practices/runtime-performance/on-push-trigger.svg">
|
||||
|
||||
```mermaid
|
||||
graph TD;
|
||||
app[AppComponent] --- header[HeaderComponent];
|
||||
|
||||
@@ -35,7 +35,7 @@ class AppComponent implements OnInit {
|
||||
|
||||
The preceding snippet instructs Angular to call `setInterval` outside the Angular Zone and skip running change detection after `pollForUpdates` runs.
|
||||
|
||||
Third-party libraries commonly trigger unnecessary change detection cycles because they weren't authored with Zone.js in mind. Avoid these extra cycles by calling library APIs outside the Angular zone:
|
||||
Third-party libraries commonly trigger unnecessary change detection cycles when their APIs are invoked within the Angular zone. This phenomenon particularly affects libraries that setup event listeners or initiate other tasks (such as timers, XHR requests, etc.). Avoid these extra cycles by calling library APIs outside the Angular zone:
|
||||
|
||||
<docs-code header="Move the plot initialization outside of the Zone" language='ts' linenums>
|
||||
import { Component, NgZone, OnInit } from '@angular/core';
|
||||
@@ -57,3 +57,67 @@ class AppComponent implements OnInit {
|
||||
Running `Plotly.newPlot('chart', data);` within `runOutsideAngular` instructs the framework that it shouldn’t run change detection after the execution of tasks scheduled by the initialization logic.
|
||||
|
||||
For example, if `Plotly.newPlot('chart', data)` adds event listeners to a DOM element, Angular does not run change detection after the execution of their handlers.
|
||||
|
||||
But sometimes, you may need to listen to events dispatched by third-party APIs. In such cases, it's important to remember that those event listeners will also execute outside of the Angular zone if the initialization logic was done there:
|
||||
|
||||
<docs-code header="Check whether the handler is called outside of the Zone" language='ts' linenums>
|
||||
import { Component, NgZone, OnInit, output } from '@angular/core';
|
||||
import * as Plotly from 'plotly.js-dist-min';
|
||||
|
||||
@Component(...)
|
||||
class AppComponent implements OnInit {
|
||||
plotlyClick = output<Plotly.PlotMouseEvent>();
|
||||
|
||||
constructor(private ngZone: NgZone) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.ngZone.runOutsideAngular(() => {
|
||||
this.createPlotly();
|
||||
});
|
||||
}
|
||||
|
||||
private async createPlotly() {
|
||||
const plotly = await Plotly.newPlot('chart', data);
|
||||
|
||||
plotly.on('plotly_click', (event: Plotly.PlotMouseEvent) => {
|
||||
// This handler will be called outside of the Angular zone because
|
||||
// the initialization logic is also called outside of the zone. To check
|
||||
// whether we're in the Angular zone, we can call the following:
|
||||
console.log(NgZone.isInAngularZone());
|
||||
this.plotlyClick.emit(event);
|
||||
});
|
||||
}
|
||||
}
|
||||
</docs-code>
|
||||
|
||||
If you need to dispatch events to parent components and execute specific view update logic, you should consider re-entering the Angular zone to instruct the framework to run change detection or run change detection manually:
|
||||
|
||||
<docs-code header="Re-enter the Angular zone when dispatching event" language='ts' linenums>
|
||||
import { Component, NgZone, OnInit, output } from '@angular/core';
|
||||
import * as Plotly from 'plotly.js-dist-min';
|
||||
|
||||
@Component(...)
|
||||
class AppComponent implements OnInit {
|
||||
plotlyClick = output<Plotly.PlotMouseEvent>();
|
||||
|
||||
constructor(private ngZone: NgZone) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.ngZone.runOutsideAngular(() => {
|
||||
this.createPlotly();
|
||||
});
|
||||
}
|
||||
|
||||
private async createPlotly() {
|
||||
const plotly = await Plotly.newPlot('chart', data);
|
||||
|
||||
plotly.on('plotly_click', (event: Plotly.PlotMouseEvent) => {
|
||||
this.ngZone.run(() => {
|
||||
this.plotlyClick.emit(event);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
</docs-code>
|
||||
|
||||
The scenario of dispatching events outside of the Angular zone may also arise. It's important to remember that triggering change detection (for example, manually) may result to the creation/update of views outside of the Angular zone.
|
||||
@@ -5,6 +5,8 @@ It can improve the user experience by quickly launching a static rendered page (
|
||||
|
||||
This gives users a meaningful first paint of your application that appears quickly because the browser can render the HTML and CSS without the need to initialize any JavaScript.
|
||||
|
||||
Learn more in [The App Shell Model](https://developers.google.com/web/fundamentals/architecture/app-shell).
|
||||
|
||||
<docs-workflow>
|
||||
<docs-step title="Prepare the application">
|
||||
Do this with the following Angular CLI command:
|
||||
@@ -15,7 +17,7 @@ ng new my-app --routing
|
||||
|
||||
</docs-code>
|
||||
|
||||
For an existing application, you have to manually add the `RouterModule` and defining a `<router-outlet>` within your application.
|
||||
For an existing application, you have to manually add the `Router` and defining a `<router-outlet>` within your application.
|
||||
</docs-step>
|
||||
<docs-step title="Create the application shell">
|
||||
Use the Angular CLI to automatically create the application shell.
|
||||
@@ -28,57 +30,24 @@ ng generate app-shell
|
||||
|
||||
For more information about this command, see [App shell command](cli/generate#app-shell-command).
|
||||
|
||||
After running this command you can see that the `angular.json` configuration file has been updated to add two new targets, with a few other changes.
|
||||
The command updates the application code and adds extra files to the project structure.
|
||||
|
||||
<docs-code language="json">
|
||||
<code-example language="text">
|
||||
|
||||
src
|
||||
├── app
|
||||
│ ├── app.config.server.ts # server application configuration
|
||||
│ └── app-shell # app-shell component
|
||||
│ ├── app-shell.component.html
|
||||
│ ├── app-shell.component.scss
|
||||
│ ├── app-shell.component.spec.ts
|
||||
│ └── app-shell.component.ts
|
||||
└── main.server.ts # main server application bootstrapping
|
||||
|
||||
</code-example>
|
||||
|
||||
"server": {
|
||||
"builder": "@angular-devkit/build-angular:server",
|
||||
"defaultConfiguration": "production",
|
||||
"options": {
|
||||
"outputPath": "dist/my-app/server",
|
||||
"main": "src/main.server.ts",
|
||||
"tsConfig": "tsconfig.server.json"
|
||||
},
|
||||
"configurations": {
|
||||
"development": {
|
||||
"outputHashing": "none",
|
||||
},
|
||||
"production": {
|
||||
"outputHashing": "media",
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"sourceMap": false,
|
||||
"optimization": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"app-shell": {
|
||||
"builder": "@angular-devkit/build-angular:app-shell",
|
||||
"defaultConfiguration": "production",
|
||||
"options": {
|
||||
"route": "shell"
|
||||
},
|
||||
"configurations": {
|
||||
"development": {
|
||||
"browserTarget": "my-app:build:development",
|
||||
"serverTarget": "my-app:server:development",
|
||||
},
|
||||
"production": {
|
||||
"browserTarget": "my-app:build:production",
|
||||
"serverTarget": "my-app:server:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</docs-code>
|
||||
</docs-step>
|
||||
<docs-step title="Verify the application is built with the shell content">
|
||||
Use the Angular CLI to build the `app-shell` target.
|
||||
|
||||
<docs-code language="shell">
|
||||
|
||||
|
||||
@@ -6,32 +6,28 @@
|
||||
|
||||
<blockquote>
|
||||
<!-- #docregion asterisk -->
|
||||
@if (hero) {<div class="name">{{ hero.name }}</div>}
|
||||
<div *ngIf="hero" class="name">{{hero.name}}</div>
|
||||
<!-- #enddocregion asterisk -->
|
||||
</blockquote>
|
||||
|
||||
<p>List of heroes</p>
|
||||
|
||||
<ul>
|
||||
@for (hero of heroes; track hero) {<li>{{ hero.name }}</li>}
|
||||
<li *ngFor="let hero of heroes">{{hero.name}}</li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2 id="ngIf">NgIf</h2>
|
||||
|
||||
@if (true) {
|
||||
<p>
|
||||
Expression is true and ngIf is true.
|
||||
This paragraph is in the DOM.
|
||||
</p>
|
||||
}
|
||||
@if (false) {
|
||||
<p>
|
||||
Expression is false and ngIf is false.
|
||||
This paragraph is not in the DOM.
|
||||
</p>
|
||||
}
|
||||
<p *ngIf="true">
|
||||
Expression is true and ngIf is true.
|
||||
This paragraph is in the DOM.
|
||||
</p>
|
||||
<p *ngIf="false">
|
||||
Expression is false and ngIf is false.
|
||||
This paragraph is not in the DOM.
|
||||
</p>
|
||||
|
||||
<p [style.display]="'block'">
|
||||
Expression sets display to "block".
|
||||
@@ -46,7 +42,7 @@
|
||||
<p><ng-template> element</p>
|
||||
<!-- #docregion ngif-template -->
|
||||
<ng-template [ngIf]="hero">
|
||||
<div class="name">{{ hero.name }}</div>
|
||||
<div class="name">{{hero.name}}</div>
|
||||
</ng-template>
|
||||
<!-- #enddocregion ngif-template -->
|
||||
|
||||
@@ -61,18 +57,18 @@
|
||||
<!-- #docregion ngif-ngcontainer -->
|
||||
<p>
|
||||
I turned the corner
|
||||
@if (hero) {
|
||||
and saw {{ hero.name }}. I waved
|
||||
}
|
||||
<ng-container *ngIf="hero">
|
||||
and saw {{hero.name}}. I waved
|
||||
</ng-container>
|
||||
and continued on my way.
|
||||
</p>
|
||||
<!-- #enddocregion ngif-ngcontainer -->
|
||||
|
||||
<p>
|
||||
I turned the corner
|
||||
@if (hero) {
|
||||
<span>and saw {{ hero.name }}. I waved</span>
|
||||
}
|
||||
<span *ngIf="hero">
|
||||
and saw {{hero.name}}. I waved
|
||||
</span>
|
||||
and continued on my way.
|
||||
</p>
|
||||
|
||||
@@ -83,15 +79,11 @@
|
||||
(<label for="show-sad"><input id="show-sad" type="checkbox" checked (change)="showSad = !showSad">show sad</label>)
|
||||
</div>
|
||||
<select [(ngModel)]="hero">
|
||||
@for (h of heroes; track h) {
|
||||
<span>
|
||||
@if (showSad || h.emotion !== 'sad') {
|
||||
<span>
|
||||
<option [ngValue]="h">{{ h.name }} ({{ h.emotion }})</option>
|
||||
</span>
|
||||
}
|
||||
<span *ngFor="let h of heroes">
|
||||
<span *ngIf="showSad || h.emotion !== 'sad'">
|
||||
<option [ngValue]="h">{{h.name}} ({{h.emotion}})</option>
|
||||
</span>
|
||||
}
|
||||
</span>
|
||||
</select>
|
||||
|
||||
<p><em><select> with <ng-container></em></p>
|
||||
@@ -101,11 +93,11 @@
|
||||
(<label for="showSad"><input id="showSad" type="checkbox" checked (change)="showSad = !showSad">show sad</label>)
|
||||
</div>
|
||||
<select [(ngModel)]="hero">
|
||||
@for (h of heroes; track h) {
|
||||
@if (showSad || h.emotion !== 'sad') {
|
||||
<option [ngValue]="h">{{ h.name }} ({{ h.emotion }})</option>
|
||||
}
|
||||
}
|
||||
<ng-container *ngFor="let h of heroes">
|
||||
<ng-container *ngIf="showSad || h.emotion !== 'sad'">
|
||||
<option [ngValue]="h">{{h.name}} ({{h.emotion}})</option>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</select>
|
||||
<!-- #enddocregion select-ngcontainer -->
|
||||
<br><br>
|
||||
@@ -118,12 +110,11 @@
|
||||
|
||||
<p class="code"><div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd"></p>
|
||||
<!--#docregion inside-ngfor -->
|
||||
@for (hero of heroes; track hero; let odd = $odd; let i = $index) {
|
||||
<div
|
||||
[class.odd]="odd">
|
||||
({{ i }}) {{ hero.name }}
|
||||
</div>
|
||||
}
|
||||
<div
|
||||
*ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById"
|
||||
[class.odd]="odd">
|
||||
({{i}}) {{hero.name}}
|
||||
</div>
|
||||
|
||||
<!--#enddocregion inside-ngfor -->
|
||||
<p class="code"><ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById"/></p>
|
||||
@@ -131,7 +122,7 @@
|
||||
<ng-template ngFor let-hero [ngForOf]="heroes"
|
||||
let-i="index" let-odd="odd" [ngForTrackBy]="trackById">
|
||||
<div [class.odd]="odd">
|
||||
({{ i }}) {{ hero.name }}
|
||||
({{i}}) {{hero.name}}
|
||||
</div>
|
||||
</ng-template>
|
||||
<!--#enddocregion inside-ngfor -->
|
||||
@@ -143,46 +134,35 @@
|
||||
|
||||
<div>Pick your favorite hero</div>
|
||||
<p>
|
||||
@for (h of heroes; track h) {
|
||||
<label for="hero-{{ h }}">
|
||||
<input id="hero-{{ h }}" type="radio" name="heroes" [(ngModel)]="hero" [value]="h">{{ h.name }}
|
||||
</label>
|
||||
}
|
||||
<label for="hero-{{h}}" *ngFor="let h of heroes">
|
||||
<input id="hero-{{h}}" type="radio" name="heroes" [(ngModel)]="hero" [value]="h">{{h.name}}
|
||||
</label>
|
||||
<label for="none-of-the-above"><input id="none-of-the-above" type="radio" name="heroes" (click)="hero = null">None of the above</label>
|
||||
</p>
|
||||
|
||||
<h4>NgSwitch</h4>
|
||||
|
||||
<div>
|
||||
@switch (hero?.emotion) {
|
||||
@case ('happy') {
|
||||
<app-happy-hero [hero]="hero!"></app-happy-hero>
|
||||
} @case ('sad') {
|
||||
<app-sad-hero [hero]="hero!"></app-sad-hero>
|
||||
} @case ('confused') {
|
||||
<app-confused-hero [hero]="hero!"></app-confused-hero>
|
||||
} @default {
|
||||
<app-unknown-hero [hero]="hero!"></app-unknown-hero>
|
||||
}
|
||||
}
|
||||
<div [ngSwitch]="hero?.emotion">
|
||||
<app-happy-hero *ngSwitchCase="'happy'" [hero]="hero!"></app-happy-hero>
|
||||
<app-sad-hero *ngSwitchCase="'sad'" [hero]="hero!"></app-sad-hero>
|
||||
<app-confused-hero *ngSwitchCase="'confused'" [hero]="hero!"></app-confused-hero>
|
||||
<app-unknown-hero *ngSwitchDefault [hero]="hero!"></app-unknown-hero>
|
||||
</div>
|
||||
|
||||
<h4>NgSwitch with <ng-template></h4>
|
||||
<div>
|
||||
@switch (hero?.emotion) {
|
||||
@case ('happy') {
|
||||
<app-happy-hero [hero]="hero!"></app-happy-hero>
|
||||
}
|
||||
@case ('sad') {
|
||||
<app-sad-hero [hero]="hero!"></app-sad-hero>
|
||||
}
|
||||
@case ('confused') {
|
||||
<app-confused-hero [hero]="hero!"></app-confused-hero>
|
||||
}
|
||||
@default {
|
||||
<app-unknown-hero [hero]="hero!"></app-unknown-hero>
|
||||
}
|
||||
}
|
||||
<div [ngSwitch]="hero?.emotion">
|
||||
<ng-template ngSwitchCase="happy">
|
||||
<app-happy-hero [hero]="hero!"></app-happy-hero>
|
||||
</ng-template>
|
||||
<ng-template ngSwitchCase="sad">
|
||||
<app-sad-hero [hero]="hero!"></app-sad-hero>
|
||||
</ng-template>
|
||||
<ng-template ngSwitchCase="confused">
|
||||
<app-confused-hero [hero]="hero!"></app-confused-hero>
|
||||
</ng-template >
|
||||
<ng-template ngSwitchDefault>
|
||||
<app-unknown-hero [hero]="hero!"></app-unknown-hero>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
@@ -192,12 +172,12 @@
|
||||
<!-- #docregion toggle-info -->
|
||||
<p>
|
||||
The condition is currently
|
||||
<span [ngClass]="{ 'a': !condition, 'b': condition, 'unless': true }">{{ condition }}</span>.
|
||||
<span [ngClass]="{ 'a': !condition, 'b': condition, 'unless': true }">{{condition}}</span>.
|
||||
<button
|
||||
type="button"
|
||||
(click)="condition = !condition"
|
||||
[ngClass]="{ 'a': condition, 'b': !condition }" >
|
||||
Toggle condition to {{ condition ? 'false' : 'true' }}
|
||||
[ngClass] = "{ 'a': condition, 'b': !condition }" >
|
||||
Toggle condition to {{condition ? 'false' : 'true'}}
|
||||
</button>
|
||||
</p>
|
||||
<!-- #enddocregion toggle-info -->
|
||||
|
||||
@@ -266,7 +266,7 @@ Learn about more advanced features in Angular animations under the Animation sec
|
||||
## Animations API summary
|
||||
|
||||
The functional API provided by the `@angular/animations` module provides a domain-specific language \(DSL\) for creating and controlling animations in Angular applications.
|
||||
See the [API reference](api/animations) for a complete listing and syntax details of the core functions and related data structures.
|
||||
See the [API reference](api#animations) for a complete listing and syntax details of the core functions and related data structures.
|
||||
|
||||
| Function name | What it does |
|
||||
|:--- |:--- |
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
# Function-based outputs
|
||||
|
||||
The `output()` function declares an output in a directive or component.
|
||||
Outputs allow you to emit values to parent components.
|
||||
|
||||
HELPFUL: The `output()` function is currently in [developer preview](/reference/releases#developer-preview).
|
||||
|
||||
<docs-code language="ts" highlight="[[5], [8]]">
|
||||
import {Component, output} from '@angular/core';
|
||||
|
||||
@Component({...})
|
||||
export class MyComp {
|
||||
onNameChange = output<string>() // OutputEmitterRef<string>
|
||||
|
||||
setNewName(newName: string) {
|
||||
this.onNameChange.emit(newName);
|
||||
}
|
||||
}
|
||||
</docs-code>
|
||||
|
||||
An output is automatically recognized by Angular whenever you use the `output` function as an initializer of a class member.
|
||||
Parent components can listen to outputs in templates by using the event binding syntax.
|
||||
|
||||
```html
|
||||
<my-comp (onNameChange)="showNewName($event)" />
|
||||
```
|
||||
|
||||
## Aliasing an output
|
||||
|
||||
Angular uses the class member name as the name of the output.
|
||||
You can alias outputs to change their public name to be different.
|
||||
|
||||
```typescript
|
||||
class MyComp {
|
||||
onNameChange = output({alias: 'ngxNameChange'});
|
||||
}
|
||||
```
|
||||
|
||||
This allows users to bind to your output using `(ngxNameChange)`, while inside your component you can access the output emitter using `this.onNameChange`.
|
||||
|
||||
## Subscribing programmatically
|
||||
|
||||
Consumers may create your component dynamically with a reference to a `ComponentRef`.
|
||||
In those cases, parents can subscribe to outputs by directly accessing the property of type `OutputRef`.
|
||||
|
||||
```ts
|
||||
const myComp = viewContainerRef.createComponent(...);
|
||||
|
||||
myComp.instance.onNameChange.subscribe(newName => {
|
||||
console.log(newName);
|
||||
});
|
||||
```
|
||||
|
||||
Angular will automatically clean up the subscription when `myComp` is destroyed.
|
||||
Alternatively, an object with a function to explicitly unsubscribe earlier is returned.
|
||||
|
||||
## Using RxJS observables as source
|
||||
|
||||
In some cases, you may want to emit output values based on RxJS observables.
|
||||
Angular provides a way to use RxJS observables as source for outputs.
|
||||
|
||||
The `outputFromObservable` function is a compiler primitive, similar to the `output()` function, and declares outputs that are driven by RxJS observables.
|
||||
|
||||
<docs-code language="ts" highlight="[7]">
|
||||
import {Directive} from '@angular/core';
|
||||
import {outputFromObservable} from '@angular/core/rxjs-interop';
|
||||
|
||||
@Directive(...)
|
||||
class MyDir {
|
||||
nameChange$ = this.dataService.get(); // Observable<Data>
|
||||
nameChange = outputFromObservable(this.nameChange$);
|
||||
}
|
||||
</docs-code>
|
||||
|
||||
Angular will forward subscriptions to the observable, but will stop forwarding values when the owning directive is destroyed.
|
||||
In the example above, if `MyDir` is destroyed, `nameChange` will no longer emit values.
|
||||
|
||||
HELPFUL: Most of the time, using `output()` is sufficient and you can emit values imperatively.
|
||||
|
||||
## Converting an output to an observable
|
||||
|
||||
You can subscribe to outputs by calling `.subscribe` method on `OutputRef`.
|
||||
In other cases, Angular provides a helper function that converts an `OutputRef` to an observable.
|
||||
|
||||
<docs-code language="ts" highlight="[11]">
|
||||
import {outputToObservable} from '@angular/core/rxjs-interop';
|
||||
|
||||
@Component(...)
|
||||
class MyComp {
|
||||
onNameChange = output<string>();
|
||||
}
|
||||
|
||||
// Instance reference to `MyComp`.
|
||||
const myComp: MyComp;
|
||||
|
||||
outputToObservable(this.myComp.instance.onNameChange) // Observable<string>
|
||||
.pipe(...)
|
||||
.subscribe(...);
|
||||
</docs-code>
|
||||
|
||||
## Why you should use `output()` over decorator-based `@Output()`?
|
||||
|
||||
The `output()` function provides numerous benefits over decorator-based `@Output` and `EventEmitter`:
|
||||
|
||||
1. Simpler mental model and API:
|
||||
<br/>• No concept of error channel, completion channels, or other APIs from RxJS.
|
||||
<br/>• Outputs are simple emitters. You can emit values using the `.emit` function.
|
||||
2. More accurate types.
|
||||
<br/>• `OutputEmitterRef.emit(value)` is now correctly typed, while `EventEmitter` has broken types and can cause runtime errors.
|
||||
@@ -56,7 +56,9 @@ Note: Certain triggers may require the presence of either a `@placeholder` or a
|
||||
|
||||
### `@loading`
|
||||
|
||||
The `@loading` block is an optional block that allows you to declare content that will be shown during the loading of any deferred dependencies. For example, you could show a loading spinner. Similar to `@placeholder`, the dependencies of the `@loading` block are eagerly loaded.
|
||||
The `@loading` block is an optional block that allows you to declare content that will be shown during the loading of any deferred dependencies. Its dependences are eagerly loaded (similar to `@placeholder`).
|
||||
|
||||
For example, you could show a loading spinner. Once loading has been triggered, the `@loading` block replaces the `@placeholder` block.
|
||||
|
||||
The `@loading` block accepts two optional parameters to specify the `minimum` amount of time that this placeholder should be shown and amount of time to wait `after` loading begins before showing the loading template. `minimum` and `after` parameters are specified in time increments of milliseconds (ms) or seconds (s). Just like `@placeholder`, these parameters exist to prevent fast flickering of content in the case that the deferred dependencies are fetched quickly. Both the `minimum` and `after` timers for the `@loading` block begins immediately after the loading has been triggered.
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
# Injection context
|
||||
|
||||
The dependency injection (DI) system relies internally on a runtime context where the current injector is available.
|
||||
This means that injectors can only work when code is executed in this context.
|
||||
This means that injectors can only work when code is executed in such a context.
|
||||
|
||||
The injection context is available in these situations:
|
||||
|
||||
* Construction (via the `constructor`) of a class being instantiated by the DI system, such as an `@Injectable` or `@Component`.
|
||||
* During construction (via the `constructor`) of a class being instantiated by the DI system, such as an `@Injectable` or `@Component`.
|
||||
* In the initializer for fields of such classes.
|
||||
* In the factory function specified for `useFactory` of a `Provider` or an `@Injectable`.
|
||||
* In the `factory` function specified for an `InjectionToken`.
|
||||
* Within a stack frame that is run in a injection context.
|
||||
* Within a stack frame that runs in an injection context.
|
||||
|
||||
Knowing when you are in an injection context, will allow you to use the [`inject`](api/core/inject) function to inject instances.
|
||||
Knowing when you are in an injection context will allow you to use the [`inject`](api/core/inject) function to inject instances.
|
||||
|
||||
## Class constructors
|
||||
|
||||
Everytime the DI system instantiates a class, this is done in an injection context. This is being handled by the framework itself. The constructor of the class is executed in that runtime context thus allowing to inject a token using the [`inject`](api/core/inject) function.
|
||||
Every time the DI system instantiates a class, it does so in an injection context. This is handled by the framework itself. The constructor of the class is executed in that runtime context, which also allows injection of a token using the [`inject`](api/core/inject) function.
|
||||
|
||||
<docs-code language="typescript" highlight="[[3],[6]]">
|
||||
class MyComponent {
|
||||
@@ -30,7 +30,7 @@ class MyComponent {
|
||||
|
||||
## Stack frame in context
|
||||
|
||||
Some APIs are designed to be run in an injection context. This is the case, for example, of the router guards. It allows the use of [`inject`](api/core/inject) to access a service within the guard function.
|
||||
Some APIs are designed to be run in an injection context. This is the case, for example, with router guards. This allows the use of [`inject`](api/core/inject) within the guard function to access a service.
|
||||
|
||||
Here is an example for `CanActivateFn`
|
||||
|
||||
@@ -43,8 +43,8 @@ const canActivateTeam: CanActivateFn =
|
||||
|
||||
## Run within an injection context
|
||||
|
||||
When you want to run a given function in an injection context without being in one, you can do it with `runInInjectionContext`.
|
||||
This requires to have access to a given injector like the `EnvironmentInjector` for example.
|
||||
When you want to run a given function in an injection context without already being in one, you can do so with `runInInjectionContext`.
|
||||
This requires access to a given injector, like the `EnvironmentInjector`, for example:
|
||||
|
||||
<docs-code header="src/app/heroes/hero.service.ts" language="typescript"
|
||||
highlight="[9]">
|
||||
@@ -66,7 +66,7 @@ Note that `inject` will return an instance only if the injector can resolve the
|
||||
|
||||
## Asserts the context
|
||||
|
||||
Angular provides `assertInInjectionContext` helper function to assert that the current context is an injection context.
|
||||
Angular provides the `assertInInjectionContext` helper function to assert that the current context is an injection context.
|
||||
|
||||
## Using DI outside of a context
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ Dependency injection, or DI, is one of the fundamental concepts in Angular. DI i
|
||||
|
||||
Two main roles exist in the DI system: dependency consumer and dependency provider.
|
||||
|
||||
Angular facilitates the interaction between dependency consumers and dependency providers using an abstraction called `Injector`. When a dependency is requested, the injector checks its registry to see if there is an instance already available there. If not, a new instance is created and stored in the registry. Angular creates an application-wide injector (also known as "root" injector) during the application bootstrap process. In most cases you don't need to manually create injectors, but you should know that there is a layer that connects providers and consumers.
|
||||
Angular facilitates the interaction between dependency consumers and dependency providers using an abstraction called `Injector`. When a dependency is requested, the injector checks its registry to see if there is an instance already available there. If not, a new instance is created and stored in the registry. Angular creates an application-wide injector (also known as the "root" injector) during the application bootstrap process. In most cases you don't need to manually create injectors, but you should know that there is a layer that connects providers and consumers.
|
||||
|
||||
This topic covers basic scenarios of how a class can act as a dependency. Angular also allows you to use functions, objects, primitive types such as string or Boolean, or any other types as dependencies. For more information, see [Dependency providers](/guide/di/dependency-injection-providers).
|
||||
|
||||
## Providing dependency
|
||||
## Providing a dependency
|
||||
|
||||
Consider there is a class called `HeroService` that needs to act as a dependency in a component.
|
||||
Consider a class called `HeroService` that needs to act as a dependency in a component.
|
||||
|
||||
The first step is to add the `@Injectable` decorator to show that the class can be injected.
|
||||
|
||||
@@ -24,7 +24,7 @@ A dependency can be provided in multiple places:
|
||||
|
||||
* [**Preferred**: At the application root level using `providedIn`.](#preferred-at-the-application-root-level-using-providedin)
|
||||
* [At the Component level.](#at-the-component-level)
|
||||
* [At application root level using `ApplicationConfig`.](#at-application-root-level-using-applicationconfig)
|
||||
* [At the application root level using `ApplicationConfig`.](#at-the-application-root-level-using-applicationconfig)
|
||||
* [`NgModule` based applications.](#ngmodule-based-applications)
|
||||
|
||||
### **Preferred**: At the application root level using `providedIn`
|
||||
@@ -64,11 +64,11 @@ When you register a provider at the component level, you get a new instance of t
|
||||
|
||||
Note: Declaring a service like this causes `HeroService` to always be included in your application— even if the service is unused.
|
||||
|
||||
### At application root level using `ApplicationConfig`
|
||||
### At the application root level using `ApplicationConfig`
|
||||
|
||||
You can use the `providers` field of the `ApplicationConfig` (passed to the `bootstrapApplication` function) to provide a service or other `Injectable` at the application level.
|
||||
|
||||
In the example below, the `HeroService` is available to all components, directives, and pipes.
|
||||
In the example below, the `HeroService` is available to all components, directives, and pipes:
|
||||
|
||||
<docs-code language="typescript" highlight="[3]">
|
||||
export const appConfig: ApplicationConfig = {
|
||||
@@ -136,5 +136,5 @@ style componentConstructor text-align: left
|
||||
## What's next
|
||||
|
||||
<docs-pill-row>
|
||||
<docs-pill href="/guide/di/creating-injectable-service" title="Creating and injecting services"/>
|
||||
<docs-pill href="/guide/di/creating-injectable-service" title="Creating an injectable service"/>
|
||||
</docs-pill-row>
|
||||
|
||||
@@ -5,7 +5,7 @@ This guide explores additional features of dependency injection in Angular.
|
||||
## Custom providers with `@Inject`
|
||||
|
||||
Using a custom provider allows you to provide a concrete implementation for implicit dependencies, such as built-in browser APIs.
|
||||
The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`.
|
||||
The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`:
|
||||
|
||||
<docs-code header="src/app/storage.service.ts" language="typescript"
|
||||
highlight="[[3,6],[12]]">
|
||||
@@ -32,8 +32,8 @@ export class BrowserStorageService {
|
||||
}
|
||||
</docs-code>
|
||||
|
||||
The `factory` function returns the `localStorage` property that is attached to the browser window object.
|
||||
The `Inject` decorator is a constructor parameter used to specify a custom provider of a dependency.
|
||||
The `factory` function returns the `localStorage` property that is attached to the browser's window object.
|
||||
The `Inject` decorator is applied to the `storage` constructor parameter and specifies a custom provider of the dependency.
|
||||
|
||||
This custom provider can now be overridden during testing with a mock API of `localStorage` instead of interacting with real browser APIs.
|
||||
|
||||
@@ -42,7 +42,7 @@ This custom provider can now be overridden during testing with a mock API of `lo
|
||||
Although developers strive to avoid it, some visual effects and third-party tools require direct DOM access.
|
||||
As a result, you might need to access a component's DOM element.
|
||||
|
||||
Angular exposes the underlying element of a `@Component` or `@Directive` via injection using the `ElementRef` injection token.
|
||||
Angular exposes the underlying element of a `@Component` or `@Directive` via injection using the `ElementRef` injection token:
|
||||
|
||||
<docs-code language="typescript" highlight="[7]">
|
||||
import { Directive, ElementRef } from '@angular/core';
|
||||
@@ -66,14 +66,13 @@ You can't refer directly to a class until it's been defined.
|
||||
|
||||
This isn't usually a problem, especially if you adhere to the recommended *one class per file* rule.
|
||||
But sometimes circular references are unavoidable.
|
||||
For example, when class 'A' refers to class 'B' and 'B' refers to 'A'.
|
||||
One of them has to be defined first.
|
||||
For example, when class 'A' refers to class 'B' and 'B' refers to 'A', one of them has to be defined first.
|
||||
|
||||
The Angular `forwardRef()` function creates an *indirect* reference that Angular can resolve later.
|
||||
|
||||
You face a similar problem when a class makes *a reference to itself*.
|
||||
For example in its `providers` array.
|
||||
The `providers` array is a property of the `@Component()` decorator function which must appear before the class definition.
|
||||
For example, in its `providers` array.
|
||||
The `providers` array is a property of the `@Component()` decorator function, which must appear before the class definition.
|
||||
You can break such circular references by using `forwardRef`.
|
||||
|
||||
<docs-code header="app.component.ts" language="typescript" highlight="[4]">
|
||||
|
||||
@@ -338,8 +338,8 @@ The following is an example of how the `<app-root>` and `<app-child>` view trees
|
||||
…content goes here…
|
||||
</#VIEW>
|
||||
</app-child>
|
||||
<#VIEW>
|
||||
<app-root>
|
||||
</#VIEW>
|
||||
</app-root>
|
||||
</docs-code>
|
||||
|
||||
Understanding the idea of the `<#VIEW>` demarcation is especially significant when you configure services in the component class.
|
||||
|
||||
@@ -195,33 +195,3 @@ providers.
|
||||
If a component or directive with `hostDirectives` and those host directives both provide the same
|
||||
injection token, the providers defined by class with `hostDirectives` take precedence over providers
|
||||
defined by the host directives.
|
||||
|
||||
### Performance
|
||||
|
||||
While the directive composition API offers a powerful tool for reusing common behaviors, excessive
|
||||
use of host directives can impact your application's memory use. If you create components or
|
||||
directives that use *many* host directives, you may inadvertently balloon the memory used by your
|
||||
application.
|
||||
|
||||
The following example shows a component that applies several host directives.
|
||||
|
||||
```typescript
|
||||
@Component({
|
||||
standalone: true,
|
||||
hostDirectives: [
|
||||
DisabledState,
|
||||
RequiredState,
|
||||
ValidationState,
|
||||
ColorState,
|
||||
RippleBehavior,
|
||||
],
|
||||
})
|
||||
export class CustomCheckbox { }
|
||||
```
|
||||
|
||||
This example declares a custom checkbox component that includes five host directives. This
|
||||
means that Angular will create six objects each time a `CustomCheckbox` renders— one for the
|
||||
component and one for each host directive. For a few checkboxes on a page, this won't pose any
|
||||
significant issues. However, if your page renders *hundreds* of checkboxes, such as in a table, then
|
||||
you could start to see an impact of the additional object allocations. Always be sure to profile
|
||||
your application to determine the right composition pattern for your use case.
|
||||
|
||||
@@ -8,12 +8,13 @@ At the end, tests can verify that the app made no unexpected requests.
|
||||
|
||||
## Setup for testing
|
||||
|
||||
To begin testing usage of `HttpClient`, configure `TestBed` and include `provideHttpClientTesting` in your test's setup. This configures `HttpClient` to use a test backend instead of the real network. It also provides `HttpTestingController`, which you'll use to interact with the test backend, set expectations about which requests have been made, and flush responses to those requests. `HttpTestingController` can be injected from `TestBed` once configured.
|
||||
To begin testing usage of `HttpClient`, configure `TestBed` and include `provideHttpClient()` and `provideHttpClientTesting` in your test's setup. This configures `HttpClient` to use a test backend instead of the real network. It also provides `HttpTestingController`, which you'll use to interact with the test backend, set expectations about which requests have been made, and flush responses to those requests. `HttpTestingController` can be injected from `TestBed` once configured.
|
||||
|
||||
<docs-code language="ts">
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
// ... other test providers
|
||||
provideHttpClient(),
|
||||
provideHttpClientTesting(),
|
||||
],
|
||||
});
|
||||
@@ -31,6 +32,7 @@ For example, you can write a test that expects a GET request to occur and provid
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
ConfigService,
|
||||
provideHttpClient(),
|
||||
provideHttpClientTesting(),
|
||||
],
|
||||
});
|
||||
|
||||
@@ -118,17 +118,17 @@ IMPORTANT: For the "fill" image to render properly, its parent element **must**
|
||||
|
||||
NgOptimizedImage can display an automatic low-resolution placeholder for your image if you're using a CDN or image host that provides automatic image resizing. Take advantage of this feature by adding the `placeholder` attribute to your image:
|
||||
|
||||
<code-example format="typescript" language="typescript">
|
||||
<docs-code format="typescript" language="typescript">
|
||||
|
||||
<img ngSrc="cat.jpg" width="400" height="200" placeholder>
|
||||
|
||||
</code-example>
|
||||
</docs-code>
|
||||
|
||||
Adding this attribute automatically requests a second, smaller version of the image using your specified image loader. This small image will be applied as a `background-image` style with a CSS blur while your image loads. If no image loader is provided, no placeholder image can be generated and an error will be thrown.
|
||||
|
||||
The default size for generated placeholders is 30px wide. You can change this size by specifying a pixel value in the `IMAGE_CONFIG` provider, as seen below:
|
||||
|
||||
<code-example format="typescript" language="typescript">
|
||||
<docs-code format="typescript" language="typescript">
|
||||
providers: [
|
||||
{
|
||||
provide: IMAGE_CONFIG,
|
||||
@@ -137,7 +137,7 @@ providers: [
|
||||
}
|
||||
},
|
||||
],
|
||||
</code-example>
|
||||
</docs-code>
|
||||
|
||||
If you want sharp edges around your blurred placeholder, you can wrap your image in a containing `<div>` with the `overflow: hidden` style. As long as the `<div>` is the same size as the image (such as by using the `width: fit-content` style), the "fuzzy edges" of the placeholder will be hidden.
|
||||
|
||||
@@ -145,11 +145,11 @@ If you want sharp edges around your blurred placeholder, you can wrap your image
|
||||
|
||||
You can also specify a placeholder using a base64 [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs) without an image loader. The data url format is `data:image/[imagetype];[data]`, where `[imagetype]` is the image format, just as `png`, and `[data]` is a base64 encoding of the image. That encoding can be done using the command line or in JavaScript. For specific commands, see [the MDN documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs#encoding_data_into_base64_format). An example of a data URL placeholder with truncated data is shown below:
|
||||
|
||||
<code-example format="typescript" language="typescript">
|
||||
<docs-code format="typescript" language="typescript">
|
||||
|
||||
<img ngSrc="cat.jpg" width="400" height="200" placeholder="data:image/png;base64,iVBORw0K...">
|
||||
|
||||
</code-example>
|
||||
</docs-code>
|
||||
|
||||
However, large data URLs increase the size of your Angular bundles and slow down page load. If you cannot use an image loader, the Angular team recommends keeping base64 placeholder images smaller than 4KB and using them exclusively on critical images. In addition to decreasing placeholder dimensions, consider changing image formats or parameters used when saving images. At very low resolutions, these parameters can have a large effect on file size.
|
||||
|
||||
@@ -157,11 +157,11 @@ However, large data URLs increase the size of your Angular bundles and slow dow
|
||||
|
||||
By default, NgOptimizedImage applies a CSS blur effect to image placeholders. To render a placeholder without blur, provide a `placeholderConfig` argument with an object that includes the `blur` property, set to false. For example:
|
||||
|
||||
<code-example format="typescript" language="typescript">
|
||||
<docs-code format="typescript" language="typescript">
|
||||
|
||||
<img ngSrc="cat.jpg" width="400" height="200" placeholder [placeholderConfig]="{blur: false}">
|
||||
|
||||
</code-example>
|
||||
</docs-code>
|
||||
|
||||
## Adjusting image styling
|
||||
|
||||
|
||||
@@ -168,12 +168,6 @@ set id(heroId: string) {
|
||||
```
|
||||
|
||||
NOTE: You can bind all route data with key, value pairs to component inputs: static or resolved route data, path parameters, matrix parameters, and query parameters.
|
||||
If you want to use the parent components route info you will need to set the router paramsInheritanceStrategy option: withRouterConfig({paramsInheritanceStrategy: 'always'})
|
||||
|
||||
</docs-step>
|
||||
|
||||
Note: You can bind all route data with key, value pairs to component inputs: static or resolved route data, path parameters, matrix parameters, and query parameters.
|
||||
|
||||
If you want to use the parent components route info you will need to set the router `paramsInheritanceStrategy` option:
|
||||
`withRouterConfig({paramsInheritanceStrategy: 'always'})`
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ These events are shown in the following table.
|
||||
| [`ChildActivationEnd`](api/router/ChildActivationEnd) | Triggered when the Router finishes activating a route's children. |
|
||||
| [`ActivationEnd`](api/router/ActivationEnd) | Triggered when the Router finishes activating a route. |
|
||||
| [`NavigationEnd`](api/router/NavigationEnd) | Triggered when navigation ends successfully. |
|
||||
| [`NavigationCancel`](api/router/NavigationCancel) | Triggered when navigation is canceled. This can happen when a Route Guard returns false during navigation, or redirects by returning a `UrlTree` or `RedirectCommand`. |
|
||||
| [`NavigationCancel`](api/router/NavigationCancel) | Triggered when navigation is canceled. This can happen when a Route Guard returns false during navigation, or redirects by returning a `UrlTree`. |
|
||||
| [`NavigationError`](api/router/NavigationError) | Triggered when navigation fails due to an unexpected error. |
|
||||
| [`Scroll`](api/router/Scroll) | Represents a scrolling event. |
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ Angular defines the following security contexts:
|
||||
| URL | Used for URL properties, such as `<a href>`. |
|
||||
| Resource URL | A URL that is loaded and executed as code, for example, in `<script src>`. |
|
||||
|
||||
Angular sanitizes untrusted values for HTML, styles, and URLs. Sanitizing resource URLs isn't possible because they contain arbitrary code.
|
||||
Angular sanitizes untrusted values for HTML and URLs. Sanitizing resource URLs isn't possible because they contain arbitrary code.
|
||||
In development mode, Angular prints a console warning when it has to change a value during sanitization.
|
||||
|
||||
### Sanitization example
|
||||
|
||||
@@ -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.
|
||||
@@ -102,3 +98,29 @@ mySignal.set(3);
|
||||
```
|
||||
|
||||
Here, only the last value (3) will be logged.
|
||||
|
||||
### `outputFromObservable`
|
||||
|
||||
`outputFromObservable(...)` declares an Angular output that emits values based on an RxJS observable.
|
||||
|
||||
```ts
|
||||
class MyDir {
|
||||
nameChange$ = new Observable<string>(/* ... */);
|
||||
nameChange = outputFromObservable(this.nameChange$); // OutputRef<string>
|
||||
}
|
||||
```
|
||||
|
||||
See more details in the [output() API guide](/guide/output-function).
|
||||
|
||||
### `outputToObservable`
|
||||
|
||||
`outputToObservable(...)` converts an Angular output to an observable.
|
||||
This allows you use integrate Angular outputs conveniently into RxJS streams.
|
||||
|
||||
```ts
|
||||
outputToObservable(myComp.instance.onNameChange)
|
||||
.pipe(...)
|
||||
.subscribe(...)
|
||||
```
|
||||
|
||||
See more details in the [output() API guide](/guide/output-function).
|
||||
|
||||
@@ -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`. The behavior of `undefined` is specifically useful when multiple bindings to the same class exist across different directives on an element.
|
||||
|
||||
## Binding to multiple CSS classes
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ If the target event name, `myClick` fails to match an output property of `ClickD
|
||||
|
||||
## Binding to keyboard events
|
||||
|
||||
You can bind to keyboard events using Angular's binding syntax. You can specify the key or code that you would like to bind to keyboard events. They `key` and `code` fields are a native part of the browser keyboard event object. By default, event binding assumes you want to use the `key` field on the keyboard event. You can also use the `code` field.
|
||||
You can bind to keyboard events using Angular's binding syntax. You can specify the key or code that you would like to bind to keyboard events. The `key` and `code` fields are a native part of the browser keyboard event object. By default, event binding assumes you want to use the `key` field on the keyboard event. You can also use the `code` field.
|
||||
|
||||
Combinations of keys can be separated by a `.` (period). For example, `keydown.enter` will allow you to bind events to the `enter` key. You can also use modifier keys, such as `shift`, `alt`, `control`, and the `command` keys from Mac. The following example shows how to bind a keyboard event to `keydown.shift.t`.
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ Please call "TestBed.compileComponents" before your test.
|
||||
|
||||
You get this test failure message when the runtime environment compiles the source code *during the tests themselves*.
|
||||
|
||||
To correct the problem, call `compileComponents()` as explained in the following [Calling compileComponents](#compile-components) section.
|
||||
To correct the problem, call `compileComponents()` as explained in the following [Calling compileComponents](#calling-compilecomponents) section.
|
||||
|
||||
## Component with a dependency
|
||||
|
||||
@@ -1015,7 +1015,7 @@ One approach is to configure the testing module from the individual pieces as in
|
||||
|
||||
HELPFUL: Notice that the `beforeEach()` is asynchronous and calls `TestBed.compileComponents` because the `HeroDetailComponent` has an external template and css file.
|
||||
|
||||
As explained in [Calling `compileComponents()`](#compile-components), these tests could be run in a non-CLI environment where Angular would have to compile them in the browser.
|
||||
As explained in [Calling `compileComponents()`](#calling-compilecomponents), these tests could be run in a non-CLI environment where Angular would have to compile them in the browser.
|
||||
|
||||
### Import a shared module
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ Here are the most important static methods, in order of likely utility.
|
||||
| Methods | Details |
|
||||
|:--- |:--- |
|
||||
| `configureTestingModule` | The testing shims \(`karma-test-shim`, `browser-test-shim`\) establish the [initial test environment](guide/testing) and a default testing module. The default testing module is configured with basic declaratives and some Angular service substitutes that every tester needs. <br /> Call `configureTestingModule` to refine the testing module configuration for a particular set of tests by adding and removing imports, declarations \(of components, directives, and pipes\), and providers. |
|
||||
| `compileComponents` | Compile the testing module asynchronously after you've finished configuring it. You **must** call this method if *any* of the testing module components have a `templateUrl` or `styleUrls` because fetching component template and style files is necessarily asynchronous. See [compileComponents](guide/testing/components-scenarios#compile-components). <br /> After calling `compileComponents`, the `TestBed` configuration is frozen for the duration of the current spec. |
|
||||
| `compileComponents` | Compile the testing module asynchronously after you've finished configuring it. You **must** call this method if *any* of the testing module components have a `templateUrl` or `styleUrls` because fetching component template and style files is necessarily asynchronous. See [compileComponents](guide/testing/components-scenarios#calling-compilecomponents). <br /> After calling `compileComponents`, the `TestBed` configuration is frozen for the duration of the current spec. |
|
||||
| `createComponent<T>` | Create an instance of a component of type `T` based on the current `TestBed` configuration. After calling `createComponent`, the `TestBed` configuration is frozen for the duration of the current spec. |
|
||||
| `overrideModule` | Replace metadata for the given `NgModule`. Recall that modules can import other modules. The `overrideModule` method can reach deeply into the current testing module to modify one of these inner modules. |
|
||||
| `overrideComponent` | Replace metadata for the given component class, which could be nested deeply within an inner module. |
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Handle user interaction in your application.
|
||||
</docs-decorative-header>
|
||||
|
||||
One of the key aspects of making applications dynamic is the ability to handle user interaction. In this guide, we'll take a look at two primary categories of user interaction: event handling and forms.
|
||||
The ability to handle user interaction and then work with - it is one of the key aspects of building dynamic applications. In this guide, we'll take a look at simple user interaction - event handling.
|
||||
|
||||
## Event Handling
|
||||
|
||||
|
||||
@@ -25,8 +25,7 @@ system" href="guide/components" link="Get started with Components">
|
||||
testable.
|
||||
</docs-card>
|
||||
<docs-card title="Get fast state updates with fine-grained reactivity based on Signals" href="guide/signals" link="Explore Angular Signals">
|
||||
Our fine-grained reactivity model, combined with compile-time optimizations, simplify development,
|
||||
and helps build faster apps by default.
|
||||
Our fine-grained reactivity model, combined with compile-time optimizations, simplifies development and helps build faster apps by default.
|
||||
|
||||
Granularly track how and where state is used throughout an application, giving the framework the power to render fast updates via highly optimized instructions.
|
||||
</docs-card>
|
||||
@@ -81,7 +80,7 @@ more">
|
||||
<docs-card title="Clear support policies and predictable release schedule" href="reference/releases" link="Versioning & releasing">
|
||||
Angular's predictable, time-based release schedule gives your organization confidence in the
|
||||
stability and backwards compatibility of the framework. Long Term Support (LTS) windows make sure
|
||||
you get critical security fixes when you need them. First party update tools, guides and automated
|
||||
you get critical security fixes when you need them. First-party update tools, guides and automated
|
||||
migration schematics help keep your apps up-to-date with the latest advancements to the framework
|
||||
and the web platform.
|
||||
</docs-card>
|
||||
@@ -91,7 +90,7 @@ more">
|
||||
|
||||
<docs-card-container>
|
||||
<docs-card title="Reach users everywhere with internationalization support" href="guide/i18n" link="Internationalization">
|
||||
Angular's internationalization features handles message translations and formatting, including
|
||||
Angular's internationalization features handle message translations and formatting, including
|
||||
support for unicode standard ICU syntax.
|
||||
</docs-card>
|
||||
<docs-card title="Protect your users with security by default" href="guide/security" link="Security">
|
||||
@@ -125,20 +124,20 @@ more">
|
||||
|
||||
<docs-card-container>
|
||||
<docs-card title="Courses, blogs and resources" href="https://devlibrary.withgoogle.com/products/angular?sort=added" link="Check out DevLibrary">
|
||||
Our community is composed of talented developers, writers, instructors, podcasters and more. The Google for Developers library is just a sample of the high quality resources available for new and experienced developers to continue developing.
|
||||
Our community is composed of talented developers, writers, instructors, podcasters, and more. The Google for Developers library is just a sample of the high quality resources available for new and experienced developers to continue developing.
|
||||
</docs-card>
|
||||
<docs-card title="Open Source" href="https://github.com/angular/angular/blob/main/CONTRIBUTING.md" link="Contribute to Angular">
|
||||
We are thankful for the open source contributors who make Angular a better framework for everyone. From fixing a typo in the docs, to adding major features, we encourage anyone interested to get started on our GitHub.
|
||||
</docs-card>
|
||||
<docs-card title="Community partnerships" href="https://developers.google.com/community/experts/directory?specialization=angular" link="Meet the Angular GDEs">
|
||||
Our team partners with individuals, educators and enterprises to ensure we consistently are supporting developers. Angular Google Developer Experts (GDEs) represent community leaders around the world educating, organizing and developing with Angular. Enterprise partnerships help ensure that Angular scales well for technology industry leaders.
|
||||
Our team partners with individuals, educators, and enterprises to ensure we consistently are supporting developers. Angular Google Developer Experts (GDEs) represent community leaders around the world educating, organizing, and developing with Angular. Enterprise partnerships help ensure that Angular scales well for technology industry leaders.
|
||||
</docs-card>
|
||||
<docs-card title="Partnering with other Google technologies">
|
||||
Angular partners closely with other Google technologies and teams to improve the web.
|
||||
|
||||
Our ongoing partnership with Chrome’s Aurora actively explores improvements to user experience across the web developing built-in performance optimizations like NgOptimizedImage and improvements to Angular’s Core Web Vitals.
|
||||
Our ongoing partnership with Chrome’s Aurora actively explores improvements to user experience across the web, developing built-in performance optimizations like NgOptimizedImage and improvements to Angular’s Core Web Vitals.
|
||||
|
||||
We are also working with [Firebase](https://firebase.google.com/), [Tensorflow](https://www.tensorflow.org/), [Flutter](https://flutter.dev/), [Material Design](https://m3.material.io/) and [Google Cloud](https://cloud.google.com/) to ensure we provide meaningful integrations across the developer workflow.
|
||||
We are also working with [Firebase](https://firebase.google.com/), [Tensorflow](https://www.tensorflow.org/), [Flutter](https://flutter.dev/), [Material Design](https://m3.material.io/), and [Google Cloud](https://cloud.google.com/) to ensure we provide meaningful integrations across the developer workflow.
|
||||
</docs-card>
|
||||
</docs-card-container>
|
||||
|
||||
|
||||
@@ -27,15 +27,15 @@ For a complete list of Angular packages, see the [API reference](api).
|
||||
|
||||
| Package name | Details |
|
||||
|:--- |:--- |
|
||||
| [`@angular/animations`](api/animations) | Angular's animations library makes it easy to define and apply animation effects such as page and list transitions. For more information, see the [Animations guide](guide/animations). |
|
||||
| [`@angular/common`](api/common) | The commonly-needed services, pipes, and directives provided by the Angular team. |
|
||||
| [`@angular/animations`](api#animations) | Angular's animations library makes it easy to define and apply animation effects such as page and list transitions. For more information, see the [Animations guide](guide/animations). |
|
||||
| [`@angular/common`](api#common) | The commonly-needed services, pipes, and directives provided by the Angular team. |
|
||||
| `@angular/compiler` | Angular's template compiler. It understands Angular templates and can convert them to code that makes the application run. |
|
||||
| `@angular/compiler-cli` | Angular's compiler which is invoked by the Angular CLI's `ng build` and `ng serve` commands. It processes Angular templates with `@angular/compiler` inside a standard TypeScript compilation. |
|
||||
| [`@angular/core`](api/core) | Critical runtime parts of the framework that are needed by every application. Includes all metadata decorators such as `@Component`, dependency injection, and component lifecycle hooks. |
|
||||
| [`@angular/forms`](api/forms) | Support for both [template-driven](guide/forms) and [reactive forms](guide/forms/reactive-forms). See [Introduction to forms](guide/forms). |
|
||||
| [`@angular/platform-browser`](api/platform-browser) | Everything DOM and browser related, especially the pieces that help render into the DOM. |
|
||||
| [`@angular/platform-browser-dynamic`](api/platform-browser-dynamic) | Includes [providers](api/core/Provider) and methods to compile and run the application on the client using the [JIT compiler](tools/cli/aot-compiler#choosing-a-compiler). |
|
||||
| [`@angular/router`](api/router) | The router module navigates among your application pages when the browser URL changes. For more information, see [Routing and Navigation](guide/routing). |
|
||||
| [`@angular/core`](api#core) | Critical runtime parts of the framework that are needed by every application. Includes all metadata decorators such as `@Component`, dependency injection, and component lifecycle hooks. |
|
||||
| [`@angular/forms`](api#forms) | Support for both [template-driven](guide/forms) and [reactive forms](guide/forms/reactive-forms). See [Introduction to forms](guide/forms). |
|
||||
| [`@angular/platform-browser`](api#platform-browser) | Everything DOM and browser related, especially the pieces that help render into the DOM. |
|
||||
| [`@angular/platform-browser-dynamic`](api#platform-browser-dynamic) | Includes [providers](api/core/Provider) and methods to compile and run the application on the client using the [JIT compiler](tools/cli/aot-compiler#choosing-a-compiler). |
|
||||
| [`@angular/router`](api#router) | The router module navigates among your application pages when the browser URL changes. For more information, see [Routing and Navigation](guide/routing). |
|
||||
| [`@angular/cli`](https://github.com/angular/angular-cli) | Contains the Angular CLI binary for running `ng` commands. |
|
||||
| [`@angular-devkit/build-angular`](https://github.com/angular/angular-cli) | Contains default CLI builders for bundling, testing, and serving Angular applications and libraries. |
|
||||
| `rxjs` | A library for reactive programming using `Observables`. |
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
| `NG01203` | [Missing value accessor](errors/NG01203) |
|
||||
| `NG02200` | [Missing Iterable Differ](errors/NG02200) |
|
||||
| `NG02800` | [JSONP support in HttpClient configuration](errors/NG02800) |
|
||||
| `NG5000` | [Hydration with unsupported Zone.js instance.](errors/NG5000) |
|
||||
| `NG05000` | [Hydration with unsupported Zone.js instance.](errors/NG5000) |
|
||||
| `NG05104` | [Root element was not found.](errors/NG05104) |
|
||||
|
||||
## Compiler errors
|
||||
|
||||
@@ -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">
|
||||
|
||||
|
||||
@@ -46,7 +46,10 @@ In this example, we’ve adapted the shield to create an Angular Signals logo va
|
||||

|
||||
</docs-step>
|
||||
|
||||
<docs-step title="Do’s and don’ts of adapting the brand">
|
||||
<docs-step title="Do’s and don’ts of using Angular's brand">
|
||||
If you are creating your own logo, we encourage differentiating your logo from ours to not cause confusion. When adapting the logo, you are free to change and adapt the colors and shape to make it your own.
|
||||
|
||||
When representing Angular with the original logo, please follow these guidelines:
|
||||

|
||||
</docs-step>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ Start developing with the latest Angular features from our roadmap. This list re
|
||||
| [Explore Angular Signals](guide/signals) | [Migrate your Angular Material to MDC](https://material.angular.io/guide/mdc-migration) |
|
||||
| [Learn about Hydration](guide/hydration) | [Migrate to Standalone APIs](reference/migrations/standalone) |
|
||||
| [Deferrable views](https://github.com/angular/angular/discussions/50716) | [Improve image performance with NgOptimizedImage](guide/image-optimization) |
|
||||
| [Built-in control flow](https://github.com/angular/angular/discussions/50719) | [Try out Inject](tutorials/learn-angular/inject-based-di) |
|
||||
| [Built-in control flow](https://github.com/angular/angular/discussions/50719) | [Try out Inject](/tutorials/learn-angular/20-inject-based-di) |
|
||||
| | [New CDK directives](https://material.angular.io/cdk/categories) |
|
||||
|
||||
## Improving the Angular developer experience
|
||||
|
||||
+2492
-942
File diff suppressed because it is too large
Load Diff
@@ -30,7 +30,7 @@ In the code editor:
|
||||
|
||||
When adding a property binding to a component tag, we use the `[attribute] = "value"` syntax to notify Angular that the assigned value should be treated as a property from the component class and not a string value.
|
||||
|
||||
The value on the right handside is the name of the property from the `HomeComponent`.
|
||||
The value on the right-hand side is the name of the property from the `HomeComponent`.
|
||||
</docs-step>
|
||||
|
||||
<docs-step title="Confirm the code still works">
|
||||
|
||||
@@ -196,6 +196,8 @@ The server is now reading data from the HTTP request but the components that rel
|
||||
|
||||
</docs-workflow>
|
||||
|
||||
Note: This lesson relies on the `fetch` browser API. For the support of interceptors, please refer to the [Http Client documentation](/guide/http)
|
||||
|
||||
Summary: In this lesson, you updated your app to use a local web server (`json-server`), and use asynchronous service methods to retrieve data.
|
||||
|
||||
Congratulations! You've successfully completed this tutorial and are ready to continue your journey with building even more complex Angular Apps.
|
||||
|
||||
+2638
-1187
File diff suppressed because it is too large
Load Diff
+2648
-1197
File diff suppressed because it is too large
Load Diff
@@ -23,12 +23,14 @@ export class AppComponent {}
|
||||
|
||||
<docs-step title="Add validation to form">
|
||||
|
||||
Every `FormControl` can be passed the `Validators` you want to use for validating the `FormControl` values. For example, if you want to make the fields for the `profileForm` required then use `Validators.required`. Update the `name` and `email` `FormControl` to be required:
|
||||
Every `FormControl` can be passed the `Validators` you want to use for validating the `FormControl` values. For example, if you want to make the `name` field in `profileForm` required then use `Validators.required`.
|
||||
For the `email` field in our Angular form, we want to ensure it's not left empty and follows a valid email address structure. We can achieve this by combining the `Validators.required` and `Validators.email` validators in an array.
|
||||
Update the `name` and `email` `FormControl`:
|
||||
|
||||
```ts
|
||||
profileForm = new FormGroup({
|
||||
name: new FormControl('', Validators.required),
|
||||
email: new FormControl('', Validators.required),
|
||||
email: new FormControl('', [Validators.required, Validators.email]),
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import {ReactiveFormsModule} from '@angular/forms';
|
||||
template: `
|
||||
<form [formGroup]="profileForm">
|
||||
<input type="text" formControlName="name" name="name" />
|
||||
<input type="email" formControlName="email" name="password" />
|
||||
<input type="email" formControlName="email" name="email" />
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
`,
|
||||
|
||||
+2680
-1217
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -9,10 +9,12 @@
|
||||
const THEME_PREFERENCE_LOCAL_STORAGE_KEY = 'themePreference';
|
||||
const DARK_MODE_CLASS_NAME = 'docs-dark-mode';
|
||||
const LIGHT_MODE_CLASS_NAME = 'docs-light-mode';
|
||||
const PREFERS_COLOR_SCHEME_DARK = '(prefers-color-scheme: dark)';
|
||||
|
||||
|
||||
const theme = localStorage.getItem(THEME_PREFERENCE_LOCAL_STORAGE_KEY) ?? 'auto';
|
||||
const prefersDark =
|
||||
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
window.matchMedia && window.matchMedia(PREFERS_COLOR_SCHEME_DARK).matches;
|
||||
const documentClassList = this.document.documentElement.classList;
|
||||
|
||||
// clearing classes before setting them.
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
// TODO(josephperrott): Figure out why this is needed now.
|
||||
import '@angular/compiler';
|
||||
|
||||
import {bootstrapApplication} from '@angular/platform-browser';
|
||||
import {appConfig} from './app/app.config';
|
||||
import {AppComponent} from './app/app.component';
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
"""Rule for filtering external NPM dependency targets to not include
|
||||
transitive dependencies onto first-party linked `HEAD` dependencies."""
|
||||
|
||||
load("@build_bazel_rules_nodejs//:providers.bzl", "ExternalNpmPackageInfo", "LinkablePackageInfo")
|
||||
|
||||
def _filter_external_npm_deps_impl(ctx):
|
||||
problematic_paths = ["external/npm/node_modules/%s" % pkg for pkg in ctx.attr.angular_packages]
|
||||
package_name = ctx.attr.target.label.package
|
||||
has_problematic_transitive_dep = package_name.startswith("@angular-devkit/")
|
||||
filtered_deps = []
|
||||
|
||||
# Note: to_list() is expensive; we need to invoke it here to get the path
|
||||
# of each transitive dependency to check if it's an angular npm package.
|
||||
for file in ctx.attr.target[DefaultInfo].default_runfiles.files.to_list():
|
||||
if not any([file.path.startswith(path) for path in problematic_paths]):
|
||||
filtered_deps.append(file)
|
||||
else:
|
||||
has_problematic_transitive_dep = True
|
||||
|
||||
filtered_depset = depset(filtered_deps)
|
||||
|
||||
providers = [
|
||||
DefaultInfo(files = filtered_depset),
|
||||
]
|
||||
|
||||
# Re-route all problematic direct dependency external NPM packages into `adev/node_modules`
|
||||
# without their transitive packages. This allows transitive dependency resolution to first look for
|
||||
# e.g. `@angular/core` in `adev/node_modules`, and falls back to top-level node modules.
|
||||
# Note: This does not handle cases where Angular dependencies are transitive in deeper layers.
|
||||
# This is something to be addressed separately via https://github.com/angular/angular/issues/54858.
|
||||
if has_problematic_transitive_dep and ctx.attr.target.label.workspace_name == "npm":
|
||||
providers.append(LinkablePackageInfo(
|
||||
package_name = package_name,
|
||||
package_path = "adev",
|
||||
path = "external/npm/node_modules/%s" % package_name,
|
||||
files = ctx.attr.target[ExternalNpmPackageInfo].direct_sources,
|
||||
))
|
||||
|
||||
return providers
|
||||
|
||||
filter_external_npm_deps = rule(
|
||||
doc = "Filter out transitive angular dependencies from a target",
|
||||
implementation = _filter_external_npm_deps_impl,
|
||||
attrs = {
|
||||
"angular_packages": attr.string_list(
|
||||
mandatory = True,
|
||||
doc = "Angular packages to filter (useful for sandbox environments without linker)",
|
||||
),
|
||||
"target": attr.label(
|
||||
mandatory = True,
|
||||
doc = "Target to filter",
|
||||
providers = [ExternalNpmPackageInfo],
|
||||
),
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,84 @@
|
||||
load("//:packages.bzl", "ALL_PACKAGES", "to_package_label")
|
||||
load("@build_bazel_rules_nodejs//internal/linker:npm_link.bzl", "npm_link")
|
||||
load("//adev/tools/local_deps:filter_external_npm_deps.bzl", "filter_external_npm_deps")
|
||||
|
||||
def ensure_local_package_deps(deps):
|
||||
"""Replaces dependencies with their local-linked variants."""
|
||||
return [":%s" % _filtered_transitives_name(dep) for dep in deps]
|
||||
|
||||
def link_local_packages(all_deps):
|
||||
"""Create targets needed for building adev against local angular packages.
|
||||
|
||||
Creates targets that link Angular packages, as well as targets to be used
|
||||
in place of any deps required to build and test adev. These targets filter
|
||||
out any transitive deps on the npm packages and must be used in place of
|
||||
any original list of deps.
|
||||
|
||||
Use the helper `ensure_local_package_deps()` to translate a list of deps
|
||||
to the equivalent "filtered" target that this rule creates.
|
||||
|
||||
Args:
|
||||
all_deps: label list of all deps required to build and test adev
|
||||
"""
|
||||
|
||||
local_angular_deps = [dep for dep in all_deps if _is_angular_dep(dep)]
|
||||
local_angular_package_names = [_angular_dep_to_pkg_name(dep) for dep in local_angular_deps]
|
||||
|
||||
# Link local angular packages in place of their npm equivalent
|
||||
for dep in local_angular_deps:
|
||||
pkg_name = _angular_dep_to_pkg_name(dep)
|
||||
npm_link(
|
||||
name = _npm_link_name(pkg_name),
|
||||
target = to_package_label(pkg_name),
|
||||
package_name = pkg_name,
|
||||
package_path = native.package_name(),
|
||||
tags = ["manual"],
|
||||
)
|
||||
|
||||
# Special case deps that must be testonly
|
||||
testonly_deps = [
|
||||
"@npm//@angular/build-tooling/bazel/browsers/chromium",
|
||||
]
|
||||
|
||||
# Stamp a corresponding target for each dep that filters out transitive
|
||||
# dependencies on external npm packages. This help the rules_nodejs linker,
|
||||
# which fails to link local packages into transitive dependencies of npm deps.
|
||||
for dep in all_deps:
|
||||
target = dep
|
||||
if dep in local_angular_deps:
|
||||
pkg_name = _angular_dep_to_pkg_name(dep)
|
||||
|
||||
# We don't need to filter transitives on local packages as they
|
||||
# depend on each other locally.
|
||||
native.alias(
|
||||
name = _filtered_transitives_name(dep),
|
||||
actual = ":%s" % _npm_link_name(pkg_name),
|
||||
tags = ["manual"],
|
||||
)
|
||||
else:
|
||||
filter_external_npm_deps(
|
||||
name = _filtered_transitives_name(dep),
|
||||
target = target,
|
||||
testonly = True if dep in testonly_deps else False,
|
||||
angular_packages = local_angular_package_names,
|
||||
tags = ["manual"],
|
||||
)
|
||||
|
||||
def _is_angular_dep(dep):
|
||||
"""Check if a dep , e.g., @npm//@angular/core corresonds to a local Angular pacakge."""
|
||||
return dep.startswith("@npm//") and (_angular_dep_to_pkg_name(dep) in ALL_PACKAGES)
|
||||
|
||||
def _angular_dep_to_pkg_name(dep):
|
||||
"""E.g., @npm//@angular/core => '@angular/core'"""
|
||||
label = Label(dep)
|
||||
return label.package
|
||||
|
||||
def _npm_link_name(pkg_name):
|
||||
return "local_head_%s" % pkg_name.replace("@", "_").replace("/", "_")
|
||||
|
||||
def _filtered_transitives_name(dep):
|
||||
if dep.startswith(":"):
|
||||
return "%s_without_transitive_deps" % dep[1:]
|
||||
else:
|
||||
label = Label(dep)
|
||||
return "%s_without_transitive_deps" % label.package.replace("@", "_").replace("/", "_")
|
||||
+4
-9
@@ -37,7 +37,6 @@
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": ["zone.js"],
|
||||
"ngswConfigPath": "src/generated/ngsw-config.json",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"webWorkerTsConfig": "tsconfig.worker.json",
|
||||
"optimization": {
|
||||
@@ -132,8 +131,7 @@
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.next.ts"
|
||||
}
|
||||
],
|
||||
"serviceWorker": true
|
||||
]
|
||||
},
|
||||
"rc": {
|
||||
"fileReplacements": [
|
||||
@@ -141,8 +139,7 @@
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.rc.ts"
|
||||
}
|
||||
],
|
||||
"serviceWorker": true
|
||||
]
|
||||
},
|
||||
"stable": {
|
||||
"fileReplacements": [
|
||||
@@ -150,8 +147,7 @@
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.stable.ts"
|
||||
}
|
||||
],
|
||||
"serviceWorker": true
|
||||
]
|
||||
},
|
||||
"archive": {
|
||||
"fileReplacements": [
|
||||
@@ -159,8 +155,7 @@
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.archive.ts"
|
||||
}
|
||||
],
|
||||
"serviceWorker": true
|
||||
]
|
||||
},
|
||||
"ci": {
|
||||
"progress": false
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"branchName": "refs/heads/main",
|
||||
"sha": "76a340c895b3fb124b07aa8a12f78202f5b8ea98"
|
||||
"branchName": "refs/heads/17.3.x",
|
||||
"sha": "792fb318cd201df2afed5512e4fdd434e0faf41c"
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
"command": "ng completion",
|
||||
"shortDescription": "Set up Angular CLI autocompletion for your terminal.",
|
||||
"longDescriptionRelativePath": "@angular/cli/src/commands/completion/long-description.md",
|
||||
"longDescription": "Setting up autocompletion configures your terminal, so pressing the `<TAB>` key while in the middle\nof typing will display various commands and options available to you. This makes it very easy to\ndiscover and use CLI commands without lots of memorization.\n\n\n\n## Automated setup\n\nThe CLI should prompt and ask to set up autocompletion for you the first time you use it (v14+).\nSimply answer \"Yes\" and the CLI will take care of the rest.\n\n```\n$ ng serve\n? Would you like to enable autocompletion? This will set up your terminal so pressing TAB while typing Angular CLI commands will show possible options and autocomplete arguments. (Enabling autocompletion will modify configuration files in your home directory.) Yes\nAppended `source <(ng completion script)` to `/home/my-username/.bashrc`. Restart your terminal or run:\n\nsource <(ng completion script)\n\nto autocomplete `ng` commands.\n\n# Serve output...\n```\n\nIf you already refused the prompt, it won't ask again. But you can run `ng completion` to\ndo the same thing automatically.\n\nThis modifies your terminal environment to load Angular CLI autocompletion, but can't update your\ncurrent terminal session. Either restart it or run `source <(ng completion script)` directly to\nenable autocompletion in your current session.\n\nTest it out by typing `ng ser<TAB>` and it should autocomplete to `ng serve`. Ambiguous arguments\nwill show all possible options and their documentation, such as `ng generate <TAB>`.\n\n## Manual setup\n\nSome users may have highly customized terminal setups, possibly with configuration files checked\ninto source control with an opinionated structure. `ng completion` only ever appends Angular's setup\nto an existing configuration file for your current shell, or creates one if none exists. If you want\nmore control over exactly where this configuration lives, you can manually set it up by having your\nshell run at startup:\n\n```bash\nsource <(ng completion script)\n```\n\nThis is equivalent to what `ng completion` will automatically set up, and gives power users more\nflexibility in their environments when desired.\n\n## Platform support\n\nAngular CLI supports autocompletion for the Bash and Zsh shells on MacOS and Linux operating\nsystems. On Windows, Git Bash and [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/)\nusing Bash or Zsh are supported.\n\n## Global install\n\nAutocompletion works by configuring your terminal to invoke the Angular CLI on startup to load the\nsetup script. This means the terminal must be able to find and execute the Angular CLI, typically\nthrough a global install that places the binary on the user's `$PATH`. If you get\n`command not found: ng`, make sure the CLI is installed globally which you can do with the `-g`\nflag:\n\n```bash\nnpm install -g @angular/cli\n```\n",
|
||||
"longDescription": "Setting up autocompletion configures your terminal, so pressing the `<TAB>` key while in the middle\nof typing will display various commands and options available to you. This makes it very easy to\ndiscover and use CLI commands without lots of memorization.\n\n\n\n## Automated setup\n\nThe CLI should prompt and ask to set up autocompletion for you the first time you use it (v14+).\nSimply answer \"Yes\" and the CLI will take care of the rest.\n\n```\n$ ng serve\n? Would you like to enable autocompletion? This will set up your terminal so pressing TAB while typing Angular CLI commands will show possible options and autocomplete arguments. (Enabling autocompletion will modify configuration files in your home directory.) Yes\nAppended `source <(ng completion script)` to `/home/my-username/.bashrc`. Restart your terminal or run:\n\nsource <(ng completion script)\n\nto autocomplete `ng` commands.\n\n# Serve output...\n```\n\nIf you already refused the prompt, it won't ask again. But you can run `ng completion` to\ndo the same thing automatically.\n\nThis modifies your terminal environment to load Angular CLI autocompletion, but can't update your\ncurrent terminal session. Either restart it or run `source <(ng completion script)` directly to\nenable autocompletion in your current session.\n\nTest it out by typing `ng ser<TAB>` and it should autocomplete to `ng serve`. Ambiguous arguments\nwill show all possible options and their documentation, such as `ng generate <TAB>`.\n\n## Manual setup\n\nSome users may have highly customized terminal setups, possibly with configuration files checked\ninto source control with an opinionated structure. `ng completion` only ever appends Angular's setup\nto an existing configuration file for your current shell, or creates one if none exists. If you want\nmore control over exactly where this configuration lives, you can manually set it up by having your\nshell run at startup:\n\n```bash\nsource <(ng completion script)\n```\n\nThis is equivalent to what `ng completion` will automatically set up, and gives power users more\nflexibility in their environments when desired.\n\n## Platform support\n\nAngular CLI supports autocompletion for the Bash and Zsh shells on MacOS and Linux operating\nsystems. On Windows, Git Bash and [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/)\nusing Bash or Zsh are supported.\n\n## Global install\n\nAutocompletion works by configuring your terminal to invoke the Angular CLI on startup to load the\nsetup script. This means the terminal must be able to find and execute the Angular CLI, typically\nthrough a global install that places the binary on the user's `$PATH`. If you get\n`command not found: ng`, make sure the CLI is installed globally which you can do with the `-g`\nflag:\n\n```bash\nnpm install -g @angular/cli\n```\n",
|
||||
"aliases": [],
|
||||
"deprecated": false,
|
||||
"options": [
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"command": "ng serve [project]",
|
||||
"shortDescription": "Builds and serves your application, rebuilding on file changes.",
|
||||
"aliases": [
|
||||
"dev",
|
||||
"s"
|
||||
],
|
||||
"deprecated": false,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This example project is special in that it is not a cli app. To run tests appropriate for this
|
||||
* project, the test command is overwritten in `aio/content/examples/rx-library/example-config.json`.
|
||||
* project, the test command is overwritten in `aio/content/examples/rx-libary/example-config.json`.
|
||||
*
|
||||
* This is an empty placeholder file to ensure that `aio/tools/examples/run-example-e2e.mjs` runs
|
||||
* tests for this project.
|
||||
|
||||
@@ -259,7 +259,7 @@ Then, import the file in the initial view of the profiler by clicking the **Choo
|
||||
|
||||
### View the injector hierarchy of your application
|
||||
|
||||
The **Injector Tree** tab lets you explore the structure of the Injectors configured in your application. Here you will see two trees representing the [injector hierarchy](guide/hierarchical-dependency-injection) of your application. One tree is your environment hierarchy, the other is your element hierarchy.
|
||||
The **Injector Tree** tab lets you explore the structure of the Injectors configured in your application. Here you will see two trees representing the [injector hiearchy](guide/hierarchical-dependency-injection) of your application. One tree is your environment hierarchy, the other is your element hierachy.
|
||||
|
||||
<div class="lightbox">
|
||||
|
||||
@@ -269,7 +269,7 @@ The **Injector Tree** tab lets you explore the structure of the Injectors config
|
||||
|
||||
### Visualize resolution paths
|
||||
|
||||
When a specific injector is selected, the path that Angular's dependency injection algorithm traverses from that injector to the root is highlighted. For element injectors, this includes highlighting the environment injectors that the dependency injection algorithm jumps to when a dependency cannot be resolved in the element hierarchy. See [resolution rules](guide/hierarchical-dependency-injection#resolution-rules) for more details about how Angular resolves resolution paths.
|
||||
When a specific injector is selected, the path that Angular's depenedency injection algorithm traverses from that injector to the root is highlighted. For element injectors, this includes highlighting the environment injectors that the dependency injection algorithm jumps to when a dependency cannot be resolved in the element hierarchy. See [resolution rules](guide/hierarchical-dependency-injection#resolution-rules) for more details about how Angular resolves resolution paths.
|
||||
|
||||
<div class="lightbox">
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ If the `application` builder is difficult for your project to adopt, `browser-es
|
||||
|
||||
A builder named `browser-esbuild` is available within the `@angular-devkit/build-angular` package that is present in an Angular CLI generated application. The builder is a drop-in replacement for the existing `browser` builder that provides the preexisting browser application build system.
|
||||
|
||||
The compatibility option was implemented to minimize the amount of changes necessary to initially migrate your applications.
|
||||
The compatiblity option was implemented to minimize the amount of changes necessary to initially migrate your applications.
|
||||
This is provided via an alternate builder (`browser-esbuild`).
|
||||
You can update the `build` target for any application target to migrate to the new build system.
|
||||
|
||||
|
||||
@@ -33,10 +33,6 @@ export class Ticker {
|
||||
Like the `async` pipe, `toSignal` subscribes to the Observable immediately, which may trigger side effects. The subscription created by
|
||||
`toSignal` automatically unsubscribes from the given Observable upon destruction of the component in which `toSignal` is called.
|
||||
|
||||
### Injection context
|
||||
|
||||
`toSignal` by default needs to run in an [injection context](/guide/dependency-injection-context), such as during construction of a component or service. If an injection context is not available, an `Injector` can instead be explicitly specified.
|
||||
|
||||
### 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,8 @@ covers [Angular versions under active support](guide/releases#actively-supported
|
||||
|
||||
| Angular | Node.js | TypeScript | RxJS |
|
||||
| ------------------ | ------------------------------------ | -------------- | ------------------ |
|
||||
| 17.1.0 | ^18.13.0 \|\| ^20.9.0 | >=5.2.0 <5.4.0 | ^6.5.3 \|\| ^7.4.0 |
|
||||
| 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.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 |
|
||||
|
||||
@@ -6,7 +6,7 @@ A few lines of TypeScript are all it takes to create your first Angular app. As
|
||||
|
||||
The code editor contains a complete Angular app.
|
||||
|
||||
<iframe src="https://stackblitz.com/github/angular/angular/tree/main/aio/content/demos/first-app?embed=1&file=src/main.ts&hideExplorer=1&hideNavigation=1" height="550" width="100%" style="border: solid 1px 777"></iframe>
|
||||
<iframe src="https://stackblitz.com/github/angular/angular/tree/17.3.x/aio/content/demos/first-app?embed=1&file=src/main.ts&hideExplorer=1&hideNavigation=1" height="550" width="100%" style="border: solid 1px 777"></iframe>
|
||||
|
||||
The Angular app in the code editor shows the TypeScript that makes a simple, but complete, Angular component.
|
||||
It imports resources from existing libraries and defines the properties of the new component.
|
||||
|
||||
@@ -51,6 +51,8 @@
|
||||
// `/generated/docs/api/forms/f_ormb_uilder.json`.
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
"redirects": [
|
||||
{"type": 301, "source": "/", "destination": "https://angular.dev/"},
|
||||
|
||||
// A random bad indexed page that used `api/api`
|
||||
{"type": 301, "source": "/api/api/:rest*", "destination": "/api/:rest*"},
|
||||
|
||||
|
||||
+9
-9
@@ -6,7 +6,7 @@
|
||||
"author": "Angular",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"postinstall": "node tools/cli-patches/patch.js && patch-package --patch-dir ../tools/npm-patches/",
|
||||
"postinstall": "node tools/cli-patches/patch.js && patch-package --patch-dir ../tools/npm-patches-aio/",
|
||||
"prebuild": "yarn setup",
|
||||
"build": "bazel build //aio:build",
|
||||
"build-prod": "yarn build --config=release",
|
||||
@@ -81,9 +81,9 @@
|
||||
"devDependencies": {
|
||||
"@angular-devkit/architect-cli": "0.1702.0-rc.0",
|
||||
"@angular-devkit/build-angular": "17.2.0-rc.0",
|
||||
"@angular-eslint/builder": "17.3.0",
|
||||
"@angular-eslint/eslint-plugin": "17.3.0",
|
||||
"@angular-eslint/eslint-plugin-template": "17.3.0",
|
||||
"@angular-eslint/builder": "17.2.1",
|
||||
"@angular-eslint/eslint-plugin": "17.2.1",
|
||||
"@angular-eslint/eslint-plugin-template": "17.2.1",
|
||||
"@angular-eslint/template-parser": "^17.0.0",
|
||||
"@angular/build-tooling": "https://github.com/angular/dev-infra-private-build-tooling-builds.git#7c4cf003cb4ac849986beaa243d7e85a893612f2",
|
||||
"@angular/cli": "17.2.0-rc.0",
|
||||
@@ -98,8 +98,8 @@
|
||||
"@types/lunr": "^2.3.3",
|
||||
"@types/node": "^12.7.9",
|
||||
"@types/trusted-types": "^2.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "7.3.1",
|
||||
"@typescript-eslint/parser": "7.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "7.2.0",
|
||||
"@typescript-eslint/parser": "7.2.0",
|
||||
"archiver": "^7.0.0",
|
||||
"assert": "^2.0.0",
|
||||
"canonical-path": "1.0.0",
|
||||
@@ -113,7 +113,7 @@
|
||||
"eslint": "8.57.0",
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-plugin-jasmine": "4.1.3",
|
||||
"eslint-plugin-jsdoc": "48.2.1",
|
||||
"eslint-plugin-jsdoc": "48.2.0",
|
||||
"eslint-plugin-prefer-arrow": "1.2.3",
|
||||
"find-free-port": "^2.0.0",
|
||||
"firebase-tools": "^13.0.0",
|
||||
@@ -138,14 +138,14 @@
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"light-server": "^2.9.1",
|
||||
"lighthouse": "^11.0.0",
|
||||
"lighthouse": "~9.0.0",
|
||||
"lighthouse-logger": "^2.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lunr": "^2.3.9",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"patch-package": "^7.0.0",
|
||||
"protractor": "~7.0.0",
|
||||
"puppeteer-core": "22.5.0",
|
||||
"puppeteer-core": "~21.3.8",
|
||||
"rehype-slug": "^4.0.1",
|
||||
"remark": "^12.0.0",
|
||||
"remark-html": "^13.0.0",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user