Compare commits

...

89 Commits

Author SHA1 Message Date
Jessica Janiuk 587093c3a5 release: cut the v16.2.3 release 2023-08-30 10:59:51 -07:00
Luis Castro dc4f77c851 docs(core): clarify InjectionToken usage (#51386)
- Emphasized the importance of using the same InjectionToken instance for both provider and injection call.
- Added examples to illustrate correct usages to prevent NullInjectorError.

PR Close #51386
2023-08-30 15:53:24 +00:00
Aristeidis Bampakos c99624d078 docs: fix casing of GitHub in navigation (#51427)
PR Close #51427
2023-08-29 23:32:37 +00:00
Aristeidis Bampakos e8a36a7b81 docs: fix casing of image alt in page not found (#51432)
PR Close #51432
2023-08-29 23:30:51 +00:00
Aristeidis Bampakos 5c4cf07f4d docs: fix casing of a11y labels in main page (#51431)
PR Close #51431
2023-08-29 23:30:12 +00:00
Aristeidis Bampakos 646fe3c5fb docs: fix typos in search results component (#51433)
PR Close #51433
2023-08-29 23:29:40 +00:00
Joey Perrott a5e98aa338 fix(devtools): remove unnecessary escaping in regex expressions (#51554)
Correct various Useless regular-expression character escape issues.

PR Close #51554
2023-08-29 21:52:34 +00:00
Joey Perrott 5c36fc784f fix(compiler-cli): remove unnecessary escaping in regex expressions (#51554)
Correct various Useless regular-expression character escape issues.

PR Close #51554
2023-08-29 21:52:34 +00:00
Joey Perrott 04c6574280 fix(animations): remove unnecessary escaping in regex expressions (#51554)
Correct various Useless regular-expression character escape issues.

PR Close #51554
2023-08-29 21:52:34 +00:00
Joey Perrott e6b301caa2 fix(core): remove unnecessary escaping in regex expressions (#51554)
Correct various Useless regular-expression character escape issues.

PR Close #51554
2023-08-29 21:52:34 +00:00
Joey Perrott 403833557b fix(docs-infra): escape the . character in regex (#51555)
Escape the `.` character in a hostnaem regex

PR Close #51555
2023-08-29 21:13:14 +00:00
Joey Perrott 97a40958b5 build: update security related package version for aio (#51562)
Update packages for security exposure

PR Close #51562
2023-08-29 20:27:00 +00:00
Joey Perrott dbd761f528 fix(compiler-cli): correct incomplete escaping (#51557)
Correct incomplete escaping and replace all instances of `

PR Close #51557
2023-08-29 19:48:26 +00:00
Joey Perrott dcd1add06f fix(core): correct incomplete escaping (#51557)
Correct incomplete escaping and replace all instances of comment delimiters

PR Close #51557
2023-08-29 19:48:26 +00:00
Joey Perrott 8081fdd22d fix(language-service): correct incomplete escaping (#51557)
Correct incomplete escaping and replace all instances of $

PR Close #51557
2023-08-29 19:48:25 +00:00
Joey Perrott 6e5b865710 build: use pin for devcontainer base image (#51556)
Use pinned verison of container image for devcontainer.

PR Close #51556
2023-08-29 18:38:55 +00:00
Gerald Monaco 0c7c852ee7 fix(core): run afterRender callbacks outside of the Angular zone (#51551)
afterRender should run outside of the Angular zone so that it does not trigger further CD cycles

PR Close #51551
2023-08-29 17:54:20 +00:00
Thomas Turrell-Croft a06140a2ca docs: add browsers switch to CI test example (#50451)
PR Close #50451
2023-08-29 17:52:10 +00:00
Andrew Kushnir 20d62603c2 fix(core): handle hydration of view containers that use component hosts as anchors (#51456)
This commit fixes an issue where serialization of a view container fails in case it uses a component host as an anchor. This fix is similar to the fix from #51247, but for cases when we insert a component (that acts as a host for a view container) deeper in a hierarchy.

Resolves #51318.

PR Close #51456
2023-08-29 16:37:50 +00:00
Shuaib hasan akib 14941b9b79 docs(docs-infra): remove inactive resource from community page (#51418)
PR Close #51418
2023-08-28 18:36:26 +00:00
Mikka 0ad738658e docs: remove MessageService information from HeroService section (#51501)
PR Close #51501
2023-08-28 16:44:57 +00:00
Joey Perrott b7732f79db ci: fix escaping for determing current stable version (#51496)
Fix the escaping for the sed command determining the stable version

PR Close #51496
2023-08-24 20:35:41 +00:00
Jeremy Elbourn 554305976b docs(docs-infra): set meta description per page (#51487)
aio currently uses the same `<meta name="Description">` content for every page. It seems like this might be causing a problem with search engine indexing such that different pages are being marked as duplicates of each other. It's unfortunately impossible to know whether this will actually fix the issue without it going live.

PR Close #51487
2023-08-24 16:44:34 +00:00
Joey Perrott 6f4a5c325d build: add AIO_PAYLOAD_TOKEN env variable (#51489)
add environement variable for deployment

PR Close #51489
2023-08-24 16:09:00 +00:00
Joey Perrott 546a8e52dd build: provide CI_BUILD_URL env variable (#51488)
Provide the link to the job workflow on github actions

PR Close #51488
2023-08-23 22:44:59 +00:00
Joey Perrott 02894382f3 ci: properly provide environment variables for aio deployment (#51484)
Provide environment variables

PR Close #51484
2023-08-23 14:44:39 -07:00
Joey Perrott fbd5d0e7b5 build: include bazel build file in aio playground code (#51485)
Include the bazel build file in the aio playground code so it contains the same bazel
targets as the regular examples.

PR Close #51485
2023-08-23 14:44:04 -07:00
Shuaib hasan akib 5af3642f65 docs(docs-infra): Update text mdn to MDN (#51470)
PR Close #51470
2023-08-23 14:41:04 -07:00
Andrew Kushnir 03fc92d448 release: cut the v16.2.2 release 2023-08-23 10:35:53 -07:00
Joey Perrott 76860b54b9 ci: correctly check aio job results (#51464)
Correctly check the aio job result to determine if we should deploy.

PR Close #51464
2023-08-22 11:41:31 -07:00
Jeevan Mahesha fb296e4dd7 docs: add MSYS2 to DEVELOPER.md (#51459)
PR Close #51459
2023-08-22 10:39:24 -07:00
Andrew Scott 157415831c refactor(router): Have router subscribe to transition events to update state (#48427)
Rather than the navigation transitions managing Router state, this
commit updates the Router to manage its own state based on ongoing
transition events. In the future, this can be abstracted even further to
have a totally separate class that manages the Router state. This would
allow the potential for swapping state manager implementations rather
than having to implement all types of state management in a single place.

One finding during tests was that unexpected errors thrown by the state management code moved
to the Router here will no longer be caught by the transition pipe's `catchError`.
This only includes calls to the following public Api methods:

* `go`, `replaceState`, `historyGo`, `isCurrentPathEqualTo` on `Location`
* `UrlSerializer.serialize`
* `UrlHandlingStrategy.merge`.

None of these methods should throw if the router is expected to function.
These might throw when tests include incomplete mocks, which is not
supported, or in cases where the actual browser methods like
`replaceState` would throw. This will already result in unexpected/unsupported
behavior. The failure case here is now arguably better - the navigation
itself still completes but the state update (either updating Router
internal state or updating the browser URL) fails separately and is
unhandled.

PR Close #48427
2023-08-22 08:04:01 -07:00
Matthieu Riegler 6208865206 docs: update versions.md for 16.2 (#51448)
PR Close #51448
2023-08-22 08:02:55 -07:00
Alan Agius 0606eca25e docs: remove update reference (#51449)
Remove reference that `--routing` was added in 8.1

PR Close #51449
2023-08-22 08:02:07 -07:00
aanchal 4fe88cf9af docs: add lang attribute in html files (#51269)
PR Close #51269
2023-08-21 16:33:44 -07:00
Aristeidis Bampakos 94a361b543 docs: review Angular elements guide (#50043)
PR Close #50043
2023-08-21 16:32:53 -07:00
mgechev bf0f80e5d6 docs: add link to developer survey 2023 (#51444)
PR Close #51444
2023-08-21 13:43:50 -07:00
Andrew Scott b0396e7164 fix(router): Ensure canceledNavigationResolution: 'computed' works on first page (#51441)
Setting the page ID is currently broken for the first page because the
helper method's second parameter is optional, which allowed the initally
`undefined` page ID to be used again when the router performs its
initial navigation.

fixes #50983

PR Close #51441
2023-08-21 13:01:59 -07:00
Mark Thompson 7f0563eb6e docs(animations): update animation docs to be standalone first (#51390)
Update the animation example files to be standalone and use boostrap application, update the documentation to prioritize standalone

PR Close #51390
2023-08-21 13:01:21 -07:00
Yann-Thomas LE MOIGNE 6dc2b22426 docs(service-worker): Miss a comma in sample (#3) (#51336)
PR Close #51336
2023-08-21 08:24:32 -07:00
Matthieu Riegler 36f434e49d fix(core): guard the jasmine hooks (#51394)
This commit fixes a regression introduced in #50063

Fixes #51382

PR Close #51394
2023-08-21 08:14:54 -07:00
Paul Gschwendtner 4b0ef5acfb ci: remove myself from pullapprove unavailability list (#51437)
Removes myself from the pullapprove unavailability list.

PR Close #51437
2023-08-21 08:14:02 -07:00
Naaajii a1e923e2f4 docs(docs-infra): fix margin on contribute page heading (#51393)
fix margin on h2 tag of contribute page being overwritten

closes #51391

PR Close #51393
2023-08-21 08:12:58 -07:00
JoostK 39ace8664b fix(compiler-cli): enforce a minimum version to be used when a library uses input transform (#51413)
Angular 16.1 introduced the input transform feature, requiring the partial compilation output to be extended
with a reference to the input transform function. This has resulted in a subtle breaking change, where older
versions of the Angular linker can no longer consume libraries that have started to use this feature.

We do try to support using a 16.1 library from an Angular 16.0 application, but if a library actually
adopts a new feature then this is no longer possible. In such cases, it is desirable to report a message
telling the user that their version of the Angular compiler is too old, as determined by the `"minVersion"`
property that is present in each partial declaration. This version would still indicate that the declaration
required at least Angular 14.0 to be compiled, but this is not accurate once input transforms are being
used. Consequently, this error would not be reported, causing a less informative error once the input transform
was being observed.

Fixes #51411

PR Close #51413
2023-08-18 07:58:54 -07:00
Matthieu Riegler 2c65ea9b40 refactor(platform-browser-dynamic): remove reexport of MetadataOverrider (#51412)
this commit removes an unnecessary re-export

PR Close #51412
2023-08-18 07:57:35 -07:00
Matthieu Riegler 3dbfabcafe docs: fix links in UpgradeAdapter (#51395)
PR Close #51395
2023-08-18 07:56:42 -07:00
Payam Valadkhan cf463a6f4f docs: add instruction how to run aio locally (#51402)
This test is part of CI and is needed in addition to tests in packages.

PR Close #51402
2023-08-17 14:00:14 -07:00
Alex Castle a43c0772ea fix(common): Allow safeUrl for ngSrc in NgOptimizedImage (#51351)
Allow safeUrl and add transformer to immediately convert ngSrc to string

PR Close #51351
2023-08-17 10:20:36 -07:00
Matthieu Riegler bd4d2bbc1e docs: fix see also links. (#51379)
These were all the @see with no links.

PR Close #51379
2023-08-17 10:18:34 -07:00
Matthieu Riegler 4a2492380c docs(docs-infra): fix docs-watch script (#51316)
With this commit we can use `yarn docs-watch` again
Fixes #51308

PR Close #51316
2023-08-17 10:17:34 -07:00
Pawel Kozlowski 4b46819ed1 release: cut the v16.2.1 release 2023-08-16 10:19:50 -07:00
Gerald Monaco 7a090eee96 refactor(core): Ensure hydration cleanup runs in the Angular zone (#51321)
Hydration cleanup needs to run in the Angular zone so that change detection will run.

PR Close #51321
2023-08-15 16:02:06 -07:00
Andrew Scott da68bead56 docs(router): Clarify how to clear secondary routes (#51376)
The example for clearing secondary outlets currently only works because
the named outlet appears at the root of the application's route config.
If developers follow this example with an outlet that is not at the
root level, they will not be able to close the outlet.
This commit updates the example to provide a more robust way
of clearing the outlet from the activated outlet component
as well as providing a warning about how the commands are applied.

Lastly, there is a small bit of guidance provided for developers who
might want to explore the ability to close an outlet from any location
in the app, without needing to be aware of the activated route.
An example of this can be found here:
https://stackblitz.com/edit/close-outlet-from-anywhere

resolves #51373
resolves #13523

PR Close #51376
2023-08-15 15:43:18 -07:00
Zoltán Szőgyényi 543b98e1f8 docs: add new UI library resource from the Tailwind CSS ecosystem (#50976)
PR Close #50976
2023-08-15 11:29:40 -07:00
Luis Castro 03619ada72 docs(common): revert format date_pipe (#51359)
PR Close #51359
2023-08-15 10:06:47 -07:00
Luis Castro d8e5316eca docs(common): add new date format example to documentation (#51359)
PR Close #51359
2023-08-15 10:06:47 -07:00
Matthieu Riegler 77efeb5933 docs: Add usage information to HttpInterceptorFn (#51236)
Simple doc addendum

PR Close #51236
2023-08-15 10:02:43 -07:00
Matthieu Riegler 252b111d1e docs: Improve host binding docs (#51326)
This commit adds the mention of the support of styles/classes/attributes in host bindings.

fixes # 44296

PR Close #51326
2023-08-15 09:54:14 -07:00
aanchal 1c41633483 docs: add the doc type attribute (#51332)
PR Close #51332
2023-08-15 09:53:06 -07:00
codestart 9f977e0f34 docs(docs-infra): fix minor typo in standalone-migration.md (#51370)
PR Close #51370
2023-08-15 09:37:47 -07:00
Quentin Dunand 3e19890967 docs: Fix Promise.then wrong parameter (#51322)
Removed the second wrong parameter from the `Promise.then()` method in the doc.
PR Close #51322
2023-08-14 15:27:37 -07:00
Andrew Scott 074fd4a5ec build: update pullapprove (#51360)
update pullapprove to remove self from unavailable list

PR Close #51360
2023-08-14 15:12:27 -07:00
Matthieu Riegler 094d733654 docs: Add Missing SSR integrity marker error doc page (#51340)
This commit adds an error doc page for error 507 : Missing SSR content integrity marker.

PR Close #51340
2023-08-14 14:39:25 -07:00
Jessica Janiuk 2fff344cd6 docs: Add CDN Optimization section to hydration guide (#51355)
This adds a section to cover the case of CDNs that have optimizations that will break both Angular and Hydration by stripping comment nodes.

PR Close #51355
2023-08-14 14:31:09 -07:00
Jeff Schiller 951ef93aa6 docs(core): Fix minor typo in comment of injector_compatibility.ts (#51324)
PR Close #51324
2023-08-14 08:56:29 -07:00
Jeff Schiller f30a49e3de docs(docs-infra): Fix minor typos in dependency-injection-context.md (#51324)
PR Close #51324
2023-08-14 08:56:29 -07:00
Joey Perrott c48e1cc4ed ci: migrate aio jobs to GHA (#51071)
Migrate aio presubmit and deploy jobs to use Github Actions

PR Close #51071
2023-08-14 08:55:31 -07:00
Sinan997 198834b731 docs: update @self() decorator explanation (#51342)
PR Close #51342
2023-08-13 16:33:16 -07:00
Matthieu Riegler 6a8c030ab1 docs(docs-infra): Hide decorator option row if empty. (#51327)
In case where the decorator option has no description nor usageNotes, we can hide that row.

PR Close #51327
2023-08-11 06:07:38 -07:00
Andrew Scott 232a8c1b8d fix(router): Apply named outlets to children empty paths not appearing in the URL (#51292)
Empty path routes are effectively 'passthrough' routes that do not
appear in the URL. When these exist in the route tree, we do not want to
apply named outlet commands to that tree location. Instead, we skip past
this location in the tree, effectively squashing/removing this
passthrough route from the tree.

fixes #50356

PR Close #51292
2023-08-10 09:18:30 -07:00
Joey Perrott 8f944e0752 ci: migrate framework tests to GHA (#51101)
Migrate framework presubmit test job to use Github Actions

PR Close #51101
2023-08-09 17:36:24 -07:00
aanchal af0c8b8fa8 docs: add legend tag to fieldset (#51259)
PR Close #51259
2023-08-09 17:18:39 -07:00
Swami ee19395672 docs: Correct statement about app.module.ts generation with --standalone flag (#51307)
The documentation incorrectly stated that the app.module.ts file is generated
when the --standalone flag is used. This is not the case, and the documentation
should accurately reflect the behavior.

Closes #51306

PR Close #51307
2023-08-09 17:16:49 -07:00
Dylan Hunn 096fdd0f59 release: cut the v16.2.0 release 2023-08-09 14:03:37 -07:00
Douglas Parker 9998bee5f4 refactor: add dgp1130 to DevTools PullApprove config (#51301)
DevTools falls under Angular Tooling and I'll probably be reviewing future PRs for the extension.
PR Close #51301
2023-08-09 10:19:27 -07:00
Gerald Monaco 95387047fd docs: Add after*Render to Component Lifecycle guide (#51291)
PR Close #51291
2023-08-09 10:18:28 -07:00
Paweł Rawicki 899e51ad8e docs: Instead of CanActivateFn, CanActivateChildFn appears in CanActivateFn docs (#51283)
A minor error is present within the documentation. Specifically, in the documentation for the CanActivateFn function, a reference is made to the CanActivateChildFn function. However, it appears that the CanActivateChildFn function is not utilized or referenced elsewhere in the documentation of CanActivateFn.
PR Close #51283
2023-08-08 10:40:54 -07:00
Matthieu Riegler 0ba2b5e5c3 refactor(animations): remove unecessary interface (#50662)
`Animation` is provided by `lib.dom`.

PR Close #50662
2023-08-07 09:26:26 -07:00
Andrew Kushnir 9f490da7e2 fix(core): handle hydration of view containers for root components (#51247)
For cases when a root component also acts as an anchor node for a ViewContainerRef (for example, when ViewContainerRef is injected in a root component), there is a need to serialize information about the component itself, as well as an LContainer that represents this ViewContainerRef. Effectively, we need to serialize 2 pieces of info: (1) hydration info for the root component itself and (2) hydration info for the ViewContainerRef instance (an LContainer). Each piece of information is included into the hydration data (in the TransferState object) separately, thus we end up with 2 ids. Since we only have 1 root element, we encode both bits of info into a single string: ids are separated by the `|` char (e.g. `10|25`, where `10` is the ngh for a component view and 25 is the `ngh` for a root view which holds LContainer).

Previously, we were only including component-related information, thus all the views in the view container remained dehydrated and duplicated (client-rendered from scratch) on the client.

Resolves #51157.

PR Close #51247
2023-08-07 09:24:26 -07:00
Matthieu Riegler b95b5b55d8 refactor(core): throw an error when hydration marker is missing from DOM (#51170) (#51276)
non-destructive hydration expects the DOM tree to have the same structure in both places.
With this commit, the app will throw an error if comments are stripped out by the http server (eg by some CDNs).

PR Close #51276
2023-08-07 09:22:51 -07:00
Matthieu Riegler 26781fd0fe refactor(core): remove unnecessary import for custom expect. (#51216)
Also adding some missing assertion after `expect()`

PR Close #51216
2023-08-07 09:22:20 -07:00
Matthieu Riegler f79fd35042 docs: add deprecation of PACKAGE_ROOT_URL (#51222)
PR Close #51222
2023-08-07 09:21:47 -07:00
Matthieu Riegler dfa772d686 refactor(core): remove unused private provider (#51222)
Both `DEFAULT_PACKAGE_URL_PROVIDER` and `ERROR_COLLECTOR_TOKEN` are unused across the project

PR Close #51222
2023-08-07 09:21:46 -07:00
Matthieu Riegler c7c0723c7f refactor(core): deprecate PACKAGE_ROOT_URL token (#51222)
Usage was removed in #43884

PR Close #51222
2023-08-07 09:21:46 -07:00
Pawel Kozlowski e01549b26b refactor(core): introduce LView and LContainer utility functions (#51191)
This refactoring adds utility functions to add / remove LView from LContainer.
Those utils are preparation for the control flow and defer work.
Existing code was refactored to use the new utility functions and avoid
any code duplication.

PR Close #51191
2023-08-04 16:00:46 -04:00
aanchal cf62063174 docs: add title tag to index file (#51266)
PR Close #51266
2023-08-04 11:29:52 -04:00
Matthieu Riegler c0c6d1d892 docs: fix missing space after full stop (#51252)
Fixes #51250

PR Close #51252
2023-08-04 11:28:36 -04:00
Andrew Kushnir d1fa6cd7d9 refactor(compiler): drop regular imports when symbols can be defer-loaded (#51171)
This commit updates the logic to drop regular imports when all symbols that it brings can be defer-loaded.
The change ensures that there is no mix of regular and dynamic imports present in a source file.

PR Close #51171
2023-08-04 11:28:07 -04:00
Alex Rickabaugh 1472515d68 release: cut the v16.2.0-rc.0 release 2023-08-02 13:20:39 -07:00
193 changed files with 2817 additions and 1208 deletions
-1
View File
@@ -6,7 +6,6 @@
node_modules
dist
aio/node_modules
aio/content/example-playground
aio/tools/examples/shared/node_modules
aio/tools/examples/shared/example-scaffold
+1 -53
View File
@@ -249,6 +249,7 @@ jobs:
- ./ng
- ./bazel_repository_cache
# TODO: Remove test job after confirmation that the GHA version is stable.
test:
executor:
name: test-browser-executor
@@ -312,48 +313,6 @@ jobs:
- notify_webhook_on_fail:
webhook_url_env_var: SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL
test_aio:
executor:
name: test-browser-executor
resource_class: 2xlarge+
steps:
- custom_attach_workspace
- init_environment
# Run all aio tests
- run:
command: yarn --cwd aio test:ci
no_output_timeout: 20m
# Check the bundle sizes.
- run: yarn --cwd aio payload-size
deploy_aio:
executor:
name: test-browser-executor
resource_class: 2xlarge+
steps:
- custom_attach_workspace
- init_environment
# Deploy angular.io to production (if necessary)
- run: setPublicVar_CI_STABLE_BRANCH
- run: yarn --cwd aio deploy-production
test_aio_local:
executor:
name: test-browser-executor
resource_class: 2xlarge+
steps:
- custom_attach_workspace
- init_environment
# Run all aio tests (with local Angular packages)
- run:
command: yarn --cwd aio test-local:ci
no_output_timeout: 20m
# Check the bundle sizes.
- run: yarn --cwd aio payload-size aio-local
# The `build-npm-packages` tasks exist for backwards-compatibility with old scripts and
# tests that rely on the pre-Bazel `dist/packages-dist` output structure (build.sh).
# Having multiple jobs that independently build in this manner duplicates some work; we build
@@ -593,15 +552,6 @@ workflows:
- legacy-unit-tests-saucelabs:
requires:
- setup
- test_aio:
requires:
- setup
- deploy_aio:
requires:
- test_aio
- test_aio_local:
requires:
- setup
- publish_packages_as_artifacts:
requires:
- build-npm-packages
@@ -610,8 +560,6 @@ workflows:
requires:
# Only publish if tests and integration tests pass
- test
# Only publish if `aio`/`docs` tests using the locally built Angular packages pass
- test_aio_local
# Get the artifacts to publish from the build-packages-dist job
# since the publishing script expects the legacy outputs layout.
- build-npm-packages
+1 -1
View File
@@ -1,7 +1,7 @@
# Image metadata and config.
# Ideally, the Node.js version should match what we use on CI.
# See `executors > default-executor` in `.circleci/config.yml`.
FROM cimg/node:16.13-browsers
FROM cimg/node:16.13-browsers@sha256:6c7a82701665dda03e92d682360fa2e4358e07dab8d1b6a7e48f7d36e3d98117
LABEL name="Angular dev environment" \
+95
View File
@@ -5,6 +5,7 @@ on:
branches:
- main
- '[0-9]+.[0-9]+.x'
- 'correct-escaping'
pull_request:
types: [opened, synchronize, reopened]
@@ -89,3 +90,97 @@ jobs:
run: yarn install --frozen-lockfile --network-timeout 100000
- name: Test all windows CI targets
run: bazel test --test_tag_filters="-browser:chromium-local" //packages/compiler-cli/...
test:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@45de46d9ba0e0689b7a846fd31ec9e241807ca71
with:
cache-node-modules: true
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@45de46d9ba0e0689b7a846fd31ec9e241807ca71
- name: Setup Bazel Remote Caching
uses: angular/dev-infra/github-actions/bazel/configure-remote@45de46d9ba0e0689b7a846fd31ec9e241807ca71
- name: Install node modules
run: yarn install --frozen-lockfile --network-timeout 100000
- name: Run CI tests for framework
run: yarn test:ci
aio:
runs-on: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@45de46d9ba0e0689b7a846fd31ec9e241807ca71
with:
cache-node-modules: true
node-module-directories: |
./aio/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@45de46d9ba0e0689b7a846fd31ec9e241807ca71
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@45de46d9ba0e0689b7a846fd31ec9e241807ca71
- name: Install node modules for aio
run: yarn install --cwd aio --frozen-lockfile
- name: Run AIO tests with upstream packages
run: yarn --cwd aio test:ci
- name: Check generated bundle sizes
run: yarn --cwd aio payload-size
aio-local:
runs-on:
labels: ubuntu-latest-4core
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@45de46d9ba0e0689b7a846fd31ec9e241807ca71
with:
cache-node-modules: true
node-module-directories: |
./aio/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@45de46d9ba0e0689b7a846fd31ec9e241807ca71
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@45de46d9ba0e0689b7a846fd31ec9e241807ca71
- name: Install node modules
run: yarn install --cwd aio --frozen-lockfile
- name: Run AIO tests with local packages
run: yarn --cwd aio test-local:ci
- name: Check generated bundle sizes
run: yarn --cwd aio payload-size aio-local
aio-deploy:
needs: [aio]
if: needs.aio.result == 'success' && github.event_name == 'push'
runs-on:
labels: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@45de46d9ba0e0689b7a846fd31ec9e241807ca71
with:
cache-node-modules: true
node-module-directories: |
./aio/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@45de46d9ba0e0689b7a846fd31ec9e241807ca71
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@45de46d9ba0e0689b7a846fd31ec9e241807ca71
- name: Install node modules for aio
run: yarn install --cwd aio --frozen-lockfile
- name: Set the stable branch environment variable
id: latest_version
run: |
echo "CI_STABLE_BRANCH=$(npm info @angular/core dist-tags.latest | sed -r 's/^\s*([0-9]+\.[0-9]+)\.[0-9]+.*$/\1.x/')" >> $GITHUB_OUTPUT
echo "CI_BRANCH=$(echo ${{ github.event.ref }} | cut -d '/' -f 3)" >> $GITHUB_OUTPUT
- name: Deploy aio to production
env:
CI_AIO_MIN_PWA_SCORE: '95'
CI_COMMIT: ${{ github.event.after }}
CI_REPO_NAME: 'angular'
CI_PULL_REQUEST: 'false'
CI_REPO_OWNER: 'angular'
CI_BUILD_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
CI_STABLE_BRANCH: ${{ steps.latest_version.outputs.CI_STABLE_BRANCH }}
CI_BRANCH: ${{ steps.latest_version.outputs.CI_BRANCH }}
CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN: ${{ secrets.AIO_DEPLOY_TOKEN }}
CI_SECRET_PAYLOAD_FIREBASE_TOKEN: ${{ secrets.AIO_PAYLOAD_TOKEN }}
run: yarn --cwd aio deploy-production
+4 -4
View File
@@ -57,9 +57,7 @@
version: 3
availability:
users_unavailable:
- atscott
- devversion
users_unavailable: []
# Meta field that goes unused by PullApprove to allow for defining aliases to be
# used throughout the config.
@@ -339,7 +337,8 @@ groups:
'aio/content/images/guide/view-encapsulation/**/{*,.*}',
'aio/content/special-elements/**/{*,.*}',
'aio/content/guide/hydration.md',
'aio/content/guide/signals.md'
'aio/content/guide/signals.md',
'aio/content/examples/injection-token/**/{*,.*}',
])
reviewers:
users:
@@ -1124,6 +1123,7 @@ groups:
users:
- AleksanderBodurri
- devversion
- dgp1130
- josephperrott
- mgechev
- twerske
+88 -89
View File
@@ -1,3 +1,91 @@
<a name="16.2.3"></a>
# 16.2.3 (2023-08-30)
### animations
| Commit | Type | Description |
| -- | -- | -- |
| [04c6574280](https://github.com/angular/angular/commit/04c65742802537c8bd725f9a7a931955a67684d9) | fix | remove unnecessary escaping in regex expressions ([#51554](https://github.com/angular/angular/pull/51554)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [dbd761f528](https://github.com/angular/angular/commit/dbd761f528a08cba0fbdd476b115e1445683cf36) | fix | correct incomplete escaping ([#51557](https://github.com/angular/angular/pull/51557)) |
| [5c36fc784f](https://github.com/angular/angular/commit/5c36fc784f292608f7485c5513aeb98e5745d17c) | fix | remove unnecessary escaping in regex expressions ([#51554](https://github.com/angular/angular/pull/51554)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [dcd1add06f](https://github.com/angular/angular/commit/dcd1add06f9facb87de89c144967cc95a2dac27c) | fix | correct incomplete escaping ([#51557](https://github.com/angular/angular/pull/51557)) |
| [20d62603c2](https://github.com/angular/angular/commit/20d62603c2f86c810fda0b3b503327dce232a6d3) | fix | handle hydration of view containers that use component hosts as anchors ([#51456](https://github.com/angular/angular/pull/51456)) |
| [e6b301caa2](https://github.com/angular/angular/commit/e6b301caa25c1532a4db2e8521bdea3f911316b1) | fix | remove unnecessary escaping in regex expressions ([#51554](https://github.com/angular/angular/pull/51554)) |
| [0c7c852ee7](https://github.com/angular/angular/commit/0c7c852ee7ba3c1943cafce4c58760eef1b0aea4) | fix | run afterRender callbacks outside of the Angular zone ([#51551](https://github.com/angular/angular/pull/51551)) |
### language-service
| Commit | Type | Description |
| -- | -- | -- |
| [8081fdd22d](https://github.com/angular/angular/commit/8081fdd22d6889f92e11cbe4c53d80bddd496a9a) | fix | correct incomplete escaping ([#51557](https://github.com/angular/angular/pull/51557)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.2.2"></a>
# 16.2.2 (2023-08-23)
### common
| Commit | Type | Description |
| -- | -- | -- |
| [a43c0772ea](https://github.com/angular/angular/commit/a43c0772ea74410b0492a178c656268a465d3b09) | fix | Allow safeUrl for ngSrc in NgOptimizedImage ([#51351](https://github.com/angular/angular/pull/51351)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [39ace8664b](https://github.com/angular/angular/commit/39ace8664b843225a75dd706236ae13e171126d3) | fix | enforce a minimum version to be used when a library uses input transform ([#51413](https://github.com/angular/angular/pull/51413)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [36f434e49d](https://github.com/angular/angular/commit/36f434e49d24f0393950299486141a121d42e044) | fix | guard the jasmine hooks ([#51394](https://github.com/angular/angular/pull/51394)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [b0396e7164](https://github.com/angular/angular/commit/b0396e7164c08e01d24d2d8411edf1ccf4b52826) | fix | Ensure `canceledNavigationResolution: 'computed'` works on first page ([#51441](https://github.com/angular/angular/pull/51441)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.2.1"></a>
# 16.2.1 (2023-08-16)
### router
| Commit | Type | Description |
| -- | -- | -- |
| [232a8c1b8d](https://github.com/angular/angular/commit/232a8c1b8dadf3f886b4bd0142613d116c865759) | fix | Apply named outlets to children empty paths not appearing in the URL ([#51292](https://github.com/angular/angular/pull/51292)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.2.0"></a>
# 16.2.0 (2023-08-09)
### benchpress
| Commit | Type | Description |
| -- | -- | -- |
| [dd850b2ab7](https://github.com/angular/angular/commit/dd850b2ab781f24065550f8a948ced498e0f1e99) | fix | correctly report GC memory amounts ([#50760](https://github.com/angular/angular/pull/50760)) |
### common
| Commit | Type | Description |
| -- | -- | -- |
| [29d358170b](https://github.com/angular/angular/commit/29d358170b046f4a6773dfdfbbd1050f54deb301) | feat | add component input binding support for NgComponentOutlet ([#51148](https://github.com/angular/angular/pull/51148)) |
| [1837efb9da](https://github.com/angular/angular/commit/1837efb9daf5c8e86a99a06ecc77bb42bc60dbb0) | feat | Allow ngSrc to be changed post-init ([#50683](https://github.com/angular/angular/pull/50683)) |
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [c27a1e61d6](https://github.com/angular/angular/commit/c27a1e61d64a67aa169086f7db11bcfd5bb7d2fc) | feat | scope selectors in @scope queries ([#50747](https://github.com/angular/angular/pull/50747)) |
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [12bad6576d](https://github.com/angular/angular/commit/12bad6576d2ffe4667118b214d9c7598ed3d8edb) | fix | libraries compiled with v16.1+ breaking with Angular framework v16.0.x ([#50714](https://github.com/angular/angular/pull/50714)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [e53d4ecf4c](https://github.com/angular/angular/commit/e53d4ecf4cfd9e64d6ba8c8b19adbb7df9cfc047) | feat | add afterRender and afterNextRender ([#50607](https://github.com/angular/angular/pull/50607)) |
| [98d262fd27](https://github.com/angular/angular/commit/98d262fd27795014ee3988b08d3c48a0dfb63c40) | feat | create injector debugging APIs ([#48639](https://github.com/angular/angular/pull/48639)) |
| [cdaa2a8a9e](https://github.com/angular/angular/commit/cdaa2a8a9eab490b55bbb841ede4f54a2656df30) | feat | support Provider type in Injector.create ([#49587](https://github.com/angular/angular/pull/49587)) |
| [9f490da7e2](https://github.com/angular/angular/commit/9f490da7e27e495cb45d2064af9091731422a6b1) | fix | handle hydration of view containers for root components ([#51247](https://github.com/angular/angular/pull/51247)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [0b14e4ef74](https://github.com/angular/angular/commit/0b14e4ef742b1c0f73d873e2c337683b60f46845) | feat | exposes the `fixture` of the `RouterTestingHarness` ([#50280](https://github.com/angular/angular/pull/50280)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.1.8"></a>
# 16.1.8 (2023-08-02)
### compiler
@@ -7,19 +95,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.2.0-next.4"></a>
# 16.2.0-next.4 (2023-07-26)
### common
| Commit | Type | Description |
| -- | -- | -- |
| [29d358170b](https://github.com/angular/angular/commit/29d358170b046f4a6773dfdfbbd1050f54deb301) | feat | add component input binding support for NgComponentOutlet ([#51148](https://github.com/angular/angular/pull/51148)) |
### http
| Commit | Type | Description |
| -- | -- | -- |
| [57e8412e53](https://github.com/angular/angular/commit/57e8412e53229b0671df02c55be52e88b66a6865) | fix | check whether `Zone` is defined ([#51119](https://github.com/angular/angular/pull/51119)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.1.7"></a>
# 16.1.7 (2023-07-26)
### http
@@ -29,15 +104,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.2.0-next.3"></a>
# 16.2.0-next.3 (2023-07-19)
### http
| Commit | Type | Description |
| -- | -- | -- |
| [c5608e5ca9](https://github.com/angular/angular/commit/c5608e5ca99805af1a3a7caf4ce28a35f3a13ebf) | fix | Run fetch request out the angular zone ([#50981](https://github.com/angular/angular/pull/50981)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.1.6"></a>
# 16.1.6 (2023-07-19)
### http
@@ -47,38 +113,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.2.0-next.2"></a>
# 16.2.0-next.2 (2023-07-13)
### animations
| Commit | Type | Description |
| -- | -- | -- |
| [a14bdfe859](https://github.com/angular/angular/commit/a14bdfe8591a33d359bf4940f4efa828499a6373) | fix | Ensure elements are removed from the cache after leave animation. ([#50929](https://github.com/angular/angular/pull/50929)) |
### common
| Commit | Type | Description |
| -- | -- | -- |
| [1837efb9da](https://github.com/angular/angular/commit/1837efb9daf5c8e86a99a06ecc77bb42bc60dbb0) | feat | Allow ngSrc to be changed post-init ([#50683](https://github.com/angular/angular/pull/50683)) |
### compiler
| Commit | Type | Description |
| -- | -- | -- |
| [c27a1e61d6](https://github.com/angular/angular/commit/c27a1e61d64a67aa169086f7db11bcfd5bb7d2fc) | feat | scope selectors in @scope queries ([#50747](https://github.com/angular/angular/pull/50747)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [031b599a55](https://github.com/angular/angular/commit/031b599a5528e1df5779695eb75b738a5a3076fe) | fix | ensure that standalone components get correct injector instances ([#50954](https://github.com/angular/angular/pull/50954)) |
| [5d6ec0336b](https://github.com/angular/angular/commit/5d6ec0336bdea22735d0ca2bbd7cfad958efbdda) | fix | handle `deref` returning `null` on `RefactiveNode`. ([#50992](https://github.com/angular/angular/pull/50992)) |
| [b66a16ec4c](https://github.com/angular/angular/commit/b66a16ec4cf42f47efeafa711ec301efeda272be) | fix | use `setTimeout` when coalescing tasks in Node.js ([#50820](https://github.com/angular/angular/pull/50820)) |
### platform-browser
| Commit | Type | Description |
| -- | -- | -- |
| [f1b629961f](https://github.com/angular/angular/commit/f1b629961f75d535982a6196e70b82f177587ebf) | perf | do not remove renderer from cache when `REMOVE_STYLES_ON_COMPONENT_DESTROY` is enabled. ([#51005](https://github.com/angular/angular/pull/51005)) |
### upgrade
| Commit | Type | Description |
| -- | -- | -- |
| [a19a87df6c](https://github.com/angular/angular/commit/a19a87df6c30a60ca997083b979a8e1e185e5b43) | fix | allow for downgraded components to work with component-router ([#50871](https://github.com/angular/angular/pull/50871)) |
| [253d756464](https://github.com/angular/angular/commit/253d7564647607804d45404152d1253993177aea) | fix | Use `takeUntil` on leaky subscription. ([#50901](https://github.com/angular/angular/pull/50901)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.1.5"></a>
# 16.1.5 (2023-07-13)
### animations
@@ -114,28 +148,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.2.0-next.1"></a>
# 16.2.0-next.1 (2023-06-28)
### benchpress
| Commit | Type | Description |
| -- | -- | -- |
| [dd850b2ab7](https://github.com/angular/angular/commit/dd850b2ab781f24065550f8a948ced498e0f1e99) | fix | correctly report GC memory amounts ([#50760](https://github.com/angular/angular/pull/50760)) |
### core
| Commit | Type | Description |
| -- | -- | -- |
| [29340a0678](https://github.com/angular/angular/commit/29340a06789652e359e61b32f1814dcd20d9bd26) | fix | expose input transform function on ComponentFactory and ComponentMirror ([#50713](https://github.com/angular/angular/pull/50713)) |
### elements
| Commit | Type | Description |
| -- | -- | -- |
| [d64864e95e](https://github.com/angular/angular/commit/d64864e95e193e46180aeaf0d634152327650871) | fix | support input transform functions ([#50713](https://github.com/angular/angular/pull/50713)) |
### platform-browser
| Commit | Type | Description |
| -- | -- | -- |
| [2b55103e94](https://github.com/angular/angular/commit/2b55103e94578ab1cb765147077e82e1228b0dbb) | fix | wait until animation completion before destroying renderer ([#50677](https://github.com/angular/angular/pull/50677)) |
| [0380564f85](https://github.com/angular/angular/commit/0380564f8562f5971cff671319439ad0f2b40a7e) | fix | wait until animation completion before destroying renderer ([#50860](https://github.com/angular/angular/pull/50860)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.1.3"></a>
# 16.1.3 (2023-06-28)
### core
@@ -154,19 +166,6 @@
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.2.0-next.0"></a>
# 16.2.0-next.0 (2023-06-21)
### compiler-cli
| Commit | Type | Description |
| -- | -- | -- |
| [12bad6576d](https://github.com/angular/angular/commit/12bad6576d2ffe4667118b214d9c7598ed3d8edb) | fix | libraries compiled with v16.1+ breaking with Angular framework v16.0.x ([#50714](https://github.com/angular/angular/pull/50714)) |
### router
| Commit | Type | Description |
| -- | -- | -- |
| [0b14e4ef74](https://github.com/angular/angular/commit/0b14e4ef742b1c0f73d873e2c337683b60f46845) | feat | exposes the `fixture` of the `RouterTestingHarness` ([#50280](https://github.com/angular/angular/pull/50280)) |
<!-- CHANGELOG SPLIT MARKER -->
<a name="16.1.2"></a>
# 16.1.2 (2023-06-21)
### http
+2 -1
View File
@@ -1,4 +1,5 @@
<html>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Your first Angular app</title>
</head>
+12
View File
@@ -0,0 +1,12 @@
@name HTML content was altered after server-side rendering
@category runtime
@shortDescription HTML content was altered after server-side rendering
@description
Angular throws this error when it detects that the content generated by server-side rendering (SSR) was altered after the rendering. The process of hydration relies on the content to be untouched after SSR, which also includes whitespaces and comment nodes. Those whitespaces and comment nodes must be retained in the HTML generated by the SSR process. Learn more in the [Hydration guide](guide/hydration#constraints).
@debugging
Typically this happens in the following cases:
* Some CDN providers have a built-in feature to remove whitespaces and comment nodes from HTML as an optimization. Please verify if there is such an option in CDN configuration and turn it off.
* If you use custom post-processing of HTML generated by SSR (as a build step), make sure that this process doesn't remove whitespaces and comment nodes.
View File
+1
View File
@@ -1,6 +1,7 @@
import { Component } from '@angular/core';
@Component({
standalone: true,
selector: 'app-about',
templateUrl: './about.component.html',
styleUrls: ['./about.component.css']
+10 -10
View File
@@ -31,15 +31,15 @@ export const slideInAnimation =
// #docregion query
query(':enter', [
style({ left: '-100%' })
]),
query(':leave', animateChild()),
], { optional: true }),
query(':leave', animateChild(), { optional: true }),
group([
query(':leave', [
animate('300ms ease-out', style({ left: '100%' }))
]),
], { optional: true }),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
]),
], { optional: true }),
]),
]),
transition('* <=> *', [
@@ -51,19 +51,19 @@ export const slideInAnimation =
left: 0,
width: '100%'
})
]),
], { optional: true }),
query(':enter', [
style({ left: '-100%' })
]),
query(':leave', animateChild()),
], { optional: true }),
query(':leave', animateChild(), { optional: true }),
group([
query(':leave', [
animate('200ms ease-out', style({ left: '100%', opacity: 0 }))
]),
], { optional: true }),
query(':enter', [
animate('300ms ease-out', style({ left: '0%' }))
]),
query('@*', animateChild())
], { optional: true }),
query('@*', animateChild(), { optional: true })
]),
])
// #enddocregion query
+1
View File
@@ -2,6 +2,7 @@
import { Component, HostBinding } from '@angular/core';
@Component({
standalone: true,
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
+3 -1
View File
@@ -11,14 +11,16 @@ import {
} from '@angular/animations';
// #enddocregion imports
import { ChildrenOutletContexts, RouterOutlet } from '@angular/router';
import { ChildrenOutletContexts, RouterLink, RouterOutlet } from '@angular/router';
import { slideInAnimation } from './animations';
// #docregion decorator, toggle-app-animations, define
@Component({
standalone: true,
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
imports: [RouterLink, RouterOutlet],
animations: [
// #enddocregion decorator
slideInAnimation
@@ -0,0 +1,15 @@
import { ApplicationConfig } from '@angular/core';
import { routes } from './app.routes';
import { provideRouter } from '@angular/router';
import { provideProtractorTestingSupport } from '@angular/platform-browser';
import { provideAnimations } from '@angular/platform-browser/animations';
export const appConfig: ApplicationConfig = {
providers: [
// needed for supporting e2e tests
provideProtractorTestingSupport(),
provideRouter(routes),
provideAnimations(),
]
};
@@ -1,112 +1,73 @@
// #docregion route-animation-data
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { OpenCloseComponent } from './open-close.component';
import { Routes } from '@angular/router';
import { OpenClosePageComponent } from './open-close-page.component';
import { OpenCloseChildComponent } from './open-close.component.4';
import { ToggleAnimationsPageComponent } from './toggle-animations-page.component';
import { StatusSliderComponent } from './status-slider.component';
import { StatusSliderPageComponent } from './status-slider-page.component';
import { ToggleAnimationsPageComponent } from './toggle-animations-page.component';
import { HeroListPageComponent } from './hero-list-page.component';
import { HeroListGroupPageComponent } from './hero-list-group-page.component';
import { HeroListGroupsComponent } from './hero-list-groups.component';
import { HeroListEnterLeavePageComponent } from './hero-list-enter-leave-page.component';
import { HeroListEnterLeaveComponent } from './hero-list-enter-leave.component';
import { HeroListAutoCalcPageComponent } from './hero-list-auto-page.component';
import { HeroListAutoComponent } from './hero-list-auto.component';
import { HomeComponent } from './home.component';
import { AboutComponent } from './about.component';
import { InsertRemoveComponent } from './insert-remove.component';
import { QueryingComponent } from './querying.component';
import { HomeComponent } from './home.component';
import { AboutComponent } from './about.component';
@NgModule({
imports: [
BrowserModule,
BrowserAnimationsModule,
RouterModule.forRoot([
{ path: '', pathMatch: 'full', redirectTo: '/enter-leave' },
{
// #docregion route-animation-data
export const routes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: '/enter-leave' },
{
path: 'open-close',
component: OpenClosePageComponent,
data: { animation: 'openClosePage' }
},
{
},
{
path: 'status',
component: StatusSliderPageComponent,
data: { animation: 'statusPage' }
},
{
},
{
path: 'toggle',
component: ToggleAnimationsPageComponent,
data: { animation: 'togglePage' }
},
{
},
{
path: 'heroes',
component: HeroListPageComponent,
data: { animation: 'filterPage' }
},
{
},
{
path: 'hero-groups',
component: HeroListGroupPageComponent,
data: { animation: 'heroGroupPage' }
},
{
},
{
path: 'enter-leave',
component: HeroListEnterLeavePageComponent,
data: { animation: 'enterLeavePage' }
},
{
},
{
path: 'auto',
component: HeroListAutoCalcPageComponent,
data: { animation: 'autoPage' }
},
{
},
{
path: 'insert-remove',
component: InsertRemoveComponent,
data: { animation: 'insertRemovePage' }
},
{
},
{
path: 'querying',
component: QueryingComponent,
data: { animation: 'queryingPage' }
},
{
},
{
path: 'home',
component: HomeComponent,
data: { animation: 'HomePage' }
},
{
},
{
path: 'about',
component: AboutComponent,
data: { animation: 'AboutPage' }
},
])
],
// #enddocregion route-animation-data
declarations: [
AppComponent,
StatusSliderComponent,
OpenCloseComponent,
OpenCloseChildComponent,
OpenClosePageComponent,
StatusSliderPageComponent,
ToggleAnimationsPageComponent,
HeroListPageComponent,
HeroListGroupsComponent,
HeroListGroupPageComponent,
HeroListEnterLeavePageComponent,
HeroListEnterLeaveComponent,
HeroListAutoCalcPageComponent,
HeroListAutoComponent,
HomeComponent,
InsertRemoveComponent,
QueryingComponent,
AboutComponent
],
bootstrap: [AppComponent]
})
export class AppModule { }
},
];
// #enddocregion route-animation-data
+4 -1
View File
@@ -1,7 +1,9 @@
import { Component } from '@angular/core';
import { HEROES } from './mock-heroes';
import { HeroListAutoComponent } from './hero-list-auto.component';
@Component({
standalone: true,
selector: 'app-hero-list-auto-page',
template: `
<section>
@@ -9,7 +11,8 @@ import { HEROES } from './mock-heroes';
<app-hero-list-auto [heroes]="heroes" (remove)="onRemove($event)"></app-hero-list-auto>
</section>
`
`,
imports: [HeroListAutoComponent]
})
export class HeroListAutoCalcPageComponent {
heroes = HEROES.slice();
+3
View File
@@ -13,11 +13,14 @@ import {
} from '@angular/animations';
import { Hero } from './hero';
import { NgFor } from '@angular/common';
@Component({
standalone: true,
selector: 'app-hero-list-auto',
templateUrl: 'hero-list-auto.component.html',
styleUrls: ['./hero-list-page.component.css'],
imports: [NgFor],
// #docregion auto-calc
animations: [
trigger('shrinkOut', [
+4 -1
View File
@@ -1,7 +1,9 @@
import { Component } from '@angular/core';
import { HEROES } from './mock-heroes';
import { HeroListEnterLeaveComponent } from './hero-list-enter-leave.component';
@Component({
standalone: true,
selector: 'app-hero-list-enter-leave-page',
template: `
<section>
@@ -9,7 +11,8 @@ import { HEROES } from './mock-heroes';
<app-hero-list-enter-leave [heroes]="heroes" (remove)="onRemove($event)"></app-hero-list-enter-leave>
</section>
`
`,
imports: [HeroListEnterLeaveComponent]
})
export class HeroListEnterLeavePageComponent {
heroes = HEROES.slice();
+3
View File
@@ -13,8 +13,10 @@ import {
} from '@angular/animations';
import { Hero } from './hero';
import { NgFor } from '@angular/common';
@Component({
standalone: true,
selector: 'app-hero-list-enter-leave',
template: `
<ul class="heroes">
@@ -28,6 +30,7 @@ import { Hero } from './hero';
</ul>
`,
styleUrls: ['./hero-list-page.component.css'],
imports: [NgFor],
// #docregion animationdef
animations: [
trigger('flyInOut', [
+4 -1
View File
@@ -1,7 +1,9 @@
import { Component } from '@angular/core';
import { HEROES } from './mock-heroes';
import { HeroListGroupsComponent } from './hero-list-groups.component';
@Component({
standalone: true,
selector: 'app-hero-list-groups-page',
template: `
<section>
@@ -9,7 +11,8 @@ import { HEROES } from './mock-heroes';
<app-hero-list-groups [heroes]="heroes" (remove)="onRemove($event)"></app-hero-list-groups>
</section>
`
`,
imports: [HeroListGroupsComponent]
})
export class HeroListGroupPageComponent {
heroes = HEROES.slice();
+3
View File
@@ -14,8 +14,10 @@ import {
} from '@angular/animations';
import { Hero } from './hero';
import { NgFor } from '@angular/common';
@Component({
standalone: true,
selector: 'app-hero-list-groups',
template: `
<ul class="heroes">
@@ -28,6 +30,7 @@ import { Hero } from './hero';
</ul>
`,
styleUrls: ['./hero-list-page.component.css'],
imports: [NgFor],
// #docregion animationdef
animations: [
trigger('flyInOut', [
+3
View File
@@ -4,10 +4,13 @@ import { Component, HostBinding, OnInit } from '@angular/core';
import { trigger, transition, animate, style, query, stagger } from '@angular/animations';
import { HEROES } from './mock-heroes';
import { Hero } from './hero';
import { NgFor } from '@angular/common';
// #docregion filter-animations
@Component({
// #enddocregion filter-animations
standalone: true,
imports: [NgFor],
selector: 'app-hero-list-page',
templateUrl: 'hero-list-page.component.html',
styleUrls: ['hero-list-page.component.css'],
+1
View File
@@ -1,6 +1,7 @@
import { Component } from '@angular/core';
@Component({
standalone: true,
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
+3
View File
@@ -1,9 +1,12 @@
// #docplaster
import { Component } from '@angular/core';
import { trigger, transition, animate, style } from '@angular/animations';
import { NgIf } from '@angular/common';
@Component({
standalone: true,
selector: 'app-insert-remove',
imports: [NgIf],
animations: [
// #docregion enter-leave-trigger
trigger('myInsertRemoveTrigger', [
+4 -1
View File
@@ -1,6 +1,8 @@
import { Component } from '@angular/core';
import { OpenCloseComponent } from './open-close.component';
@Component({
standalone: true,
selector: 'app-open-close-page',
template: `
<section>
@@ -10,7 +12,8 @@ import { Component } from '@angular/core';
<app-open-close [logging]="logging"></app-open-close>
</section>
`
`,
imports: [OpenCloseComponent]
})
export class OpenClosePageComponent {
logging = false;
@@ -2,6 +2,7 @@ import { Component } from '@angular/core';
import { trigger, transition, state, animate, style, keyframes } from '@angular/animations';
@Component({
standalone: true,
selector: 'app-open-close',
animations: [
// #docregion trigger
@@ -2,6 +2,7 @@ import { Component } from '@angular/core';
import { trigger, transition, state, animate, style } from '@angular/animations';
@Component({
standalone: true,
selector: 'app-open-close-boolean',
// #docregion trigger-boolean
animations: [
+1
View File
@@ -5,6 +5,7 @@ import { transition, trigger, useAnimation } from '@angular/animations';
import { transitionAnimation } from './animations';
@Component({
standalone: true,
selector: 'app-open-close-reusable',
animations: [
trigger('openClose', [
+1
View File
@@ -6,6 +6,7 @@ import { trigger, transition, state, animate, style } from '@angular/animations'
// #docregion toggle-animation
@Component({
// #enddocregion toggle-animation
standalone: true,
selector: 'app-open-close-toggle',
templateUrl: 'open-close.component.4.html',
styleUrls: ['open-close.component.css'],
+1
View File
@@ -4,6 +4,7 @@ import { trigger, transition, state, animate, style, AnimationEvent } from '@ang
// #docregion component, events1
@Component({
standalone: true,
selector: 'app-open-close',
// #docregion trigger-wildcard1, trigger-transition
animations: [
+3
View File
@@ -13,8 +13,10 @@ import {
} from '@angular/animations';
import { HEROES } from './mock-heroes';
import { NgIf } from '@angular/common';
@Component({
standalone: true,
selector: 'app-querying',
template: `
<nav>
@@ -31,6 +33,7 @@ import { HEROES } from './mock-heroes';
</section>
`,
styleUrls: ['./querying.component.css'],
imports: [NgIf],
animations: [
trigger('query', [
transition(':enter', [
+4 -1
View File
@@ -1,12 +1,15 @@
import { Component } from '@angular/core';
import { StatusSliderComponent } from './status-slider.component';
@Component({
standalone: true,
selector: 'app-status-slider-page',
template: `
<section>
<h2>Status Slider</h2>
<app-status-slider></app-status-slider>
</section>
`
`,
imports: [StatusSliderComponent]
})
export class StatusSliderPageComponent {}
+1
View File
@@ -2,6 +2,7 @@ import { Component } from '@angular/core';
import { trigger, transition, state, animate, style, keyframes } from '@angular/animations';
@Component({
standalone: true,
selector: 'app-status-slider',
templateUrl: 'status-slider.component.html',
styleUrls: ['status-slider.component.css'],
+4 -1
View File
@@ -1,6 +1,8 @@
import { Component } from '@angular/core';
import { OpenCloseChildComponent } from './open-close.component.4';
@Component({
standalone: true,
selector: 'app-toggle-animations-child-page',
template: `
<section>
@@ -8,6 +10,7 @@ import { Component } from '@angular/core';
<app-open-close-toggle></app-open-close-toggle>
</section>
`
`,
imports: [OpenCloseChildComponent]
})
export class ToggleAnimationsPageComponent {}
+4 -5
View File
@@ -1,6 +1,5 @@
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
bootstrapApplication(AppComponent, appConfig);
+1 -1
View File
@@ -67,6 +67,7 @@ EXAMPLES = {
"http": {"stackblitz": True, "zip": True},
"i18n": {"stackblitz": True, "zip": True},
"inputs-outputs": {"stackblitz": True, "zip": True},
"injection-token": {"stackblitz": False, "zip": False},
"interpolation": {"stackblitz": True, "zip": True},
"lazy-loading-ngmodules": {"stackblitz": True, "zip": True},
"lifecycle-hooks": {"stackblitz": True, "zip": True},
@@ -131,7 +132,6 @@ def docs_example(name, test = True, test_tags = [], test_exec_properties = {}, f
native.filegroup(
name = "files",
srcs = native.glob(["**"], exclude = [
"BUILD.bazel",
"**/node_modules/**", # Node modules may exist from the legacy setup.
]),
)
@@ -1,18 +1,22 @@
<div class="tax-return">
<div class="msg" [class.canceled]="message==='Canceled'">{{message}}</div>
<fieldset>
<legend>Tax Return</legend>
<span id=name>{{taxReturn.name}}</span>
<span id=tid>TID: {{taxReturn.tid}}</span>
</fieldset>
<fieldset>
<legend>Tax Return</legend>
<label for="income">
Income: <input id="income" [(ngModel)]="taxReturn.income" class="num">
</label>
</fieldset>
<fieldset>
<legend>Tax Return</legend>
<span>Tax: {{taxReturn.tax}}</span>
</fieldset>
<fieldset>
<legend>Tax Return</legend>
<button type="button" (click)="onSaved()">Save</button>
<button type="button" (click)="onCanceled()">Cancel</button>
<button type="button" (click)="onClose()">Close</button>
@@ -0,0 +1,7 @@
load("//aio/content/examples:examples.bzl", "docs_example")
package(default_visibility = ["//visibility:public"])
docs_example(
name = "injection-token",
)
@@ -0,0 +1,9 @@
/*
* This example project is special in that it is not a cli app. To run tests appropriate for this
* project, the test command is overwritten in `aio/content/examples/injection-token/example-config.json`.
*
* This is an empty placeholder file to ensure that `aio/tools/examples/run-example-e2e.mjs` runs
* tests for this project.
*
* TODO: Fix our infrastructure/tooling, so that this hack is not necessary.
*/
@@ -0,0 +1,8 @@
{
"tests": [
{
"cmd": "yarn",
"args": [ "tsc", "--project", "./tsconfig.app.json" ]
}
]
}
@@ -0,0 +1,26 @@
// TODO: Add unit tests for this file.
/* eslint-disable @angular-eslint/no-output-native */
// #docregion
import {Injector, InjectionToken} from '@angular/core';
interface MyInterface {
someProperty: string;
}
// #docregion InjectionToken
const TOKEN = new InjectionToken<MyInterface>('SomeToken');
// Setting up the provider using the same token instance
const providers = [
{provide: TOKEN, useValue: {someProperty: 'exampleValue'}}, // Mock value for MyInterface
];
// Creating the injector with the provider
const injector = Injector.create({providers});
// Retrieving the value using the same token instance
const myInterface = injector.get(TOKEN);
// myInterface is inferred to be MyInterface.
// #enddocregion InjectionToken
@@ -1,6 +1,6 @@
// #docregion
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
@Component({
selector: 'app-compose-message',
@@ -12,7 +12,7 @@ export class ComposeMessageComponent {
message = '';
sending = false;
constructor(private router: Router) {}
constructor(private router: Router, private route: ActivatedRoute) {}
send() {
this.sending = true;
@@ -32,7 +32,7 @@ export class ComposeMessageComponent {
closePopup() {
// Providing a `null` value to the named outlet
// clears the contents of the named outlet
this.router.navigate([{ outlets: { popup: null }}]);
this.router.navigate([{outlets: {popup: null}}], {relativeTo: this.route.parent});
}
// #enddocregion closePopup
}
@@ -1,4 +1,5 @@
<html>
<!DOCTYPE html>
<html lang="en">
<head>
<base href="/">
<title>Angular App</title>
@@ -6,4 +7,4 @@
<body>
<app-root>loading</app-root>
</body>
</html>
</html>
@@ -30,6 +30,6 @@ describe('Security E2E Tests', () => {
it('binds trusted resource URLs', async () => {
const iframe = element(By.className('e2e-iframe-trusted-src'));
expect(await iframe.getAttribute('src')).toMatch(/^https:\/\/www.youtube.com\//);
expect(await iframe.getAttribute('src')).toMatch(/^https:\/\/www\.youtube\.com\//);
});
});
@@ -2,6 +2,7 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Index</title>
<base href="/">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.js"></script>
<script src="app/ajs-bootstrap/app.module.js"></script>
+2 -2
View File
@@ -1,6 +1,6 @@
<div class="center-layout-wide">
<div class="nf-container l-flex-wrap flex-center">
<img alt="not found" src="assets/images/support/angular-404.svg" height="300" width="300"/>
<img alt="Not found" src="assets/images/support/angular-404.svg" height="300" width="300"/>
<div class="nf-response l-flex-wrap center">
<h1 class="no-anchor no-toc">Page Not Found</h1>
<p>We're sorry. The page you are looking for cannot be found.</p>
@@ -9,4 +9,4 @@
<aio-file-not-found-search></aio-file-not-found-search>
</div>
@reviewed 2022-02-28
@reviewed 2023-08-20
+12 -10
View File
@@ -1,23 +1,25 @@
# Add an animation
The main Angular modules for animations are `@angular/animations` and `@angular/platform-browser`.
When you create a new project using the Angular framework, these dependencies are automatically added to your project.
To get started with adding Angular animations to your project, import the animation-specific modules along with standard Angular capability.
## Step 1: Enabling the animations module
Import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
Import `provideAnimations` from `@angular/platform-browser/animations` and add it to the providers list in the `bootstrapApplication` function call.
```ts
bootstrapApplication(AppComponent, {
providers: [
provideAnimations(),
]
});
```
For `NgModule` based applications import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
<code-example header="src/app/app.module.ts" path="animations/src/app/app.module.1.ts"></code-example>
<div class="alert is-helpful">
**NOTE**: <br />
When you use the Angular framework to create your application, the root application module `app.module.ts` is placed in the `src/app` directory. If you are using standalone components, look at main.ts or look at your root application component.
</div>
## Step 2: Importing animation functions into component files
If you plan to use specific animation functions in component files, import those functions from `@angular/animations`.
@@ -31,4 +33,4 @@ You put the trigger that defines an animation within the `animations` metadata p
<code-example header="src/app/app.component.ts" path="animations/src/app/app.component.ts" region="decorator"></code-example>
@reviewed 2022-12-19
@reviewed 2023-08-15
+11 -3
View File
@@ -32,13 +32,21 @@ The guide assumes that you're familiar with building basic Angular apps, as desc
## Getting started
The main Angular modules for animations are `@angular/animations` and `@angular/platform-browser`.
When you create a new project using the CLI, these dependencies are automatically added to your project.
To get started with adding Angular animations to your project, import the animation-specific modules along with standard Angular functionality.
### Step 1: Enabling the animations module
Import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
Import `provideAnimations` from `@angular/platform-browser/animations` and add it to the providers list in the `bootstrapApplication` function call.
```ts
bootstrapApplication(AppComponent, {
providers: [
provideAnimations(),
]
});
```
For `NgModule` based applications import `BrowserAnimationsModule`, which introduces the animation capabilities into your Angular root application module.
<code-example header="src/app/app.module.ts" path="animations/src/app/app.module.1.ts"></code-example>
@@ -337,4 +345,4 @@ Check out this [presentation](https://www.youtube.com/watch?v=rnTK9meY5us), show
<!-- end links -->
@reviewed 2022-02-28
@reviewed 2023-08-16
@@ -1,6 +1,6 @@
# Injection context
The dependency injection (DI) system relies internaly on a runtime context where the current injector is available.
The dependency injection (DI) system relies internally on a runtime context where the current injector is available.
This means that injectors can only work when code is executed in this context.
The injection context is available in these situations:
@@ -9,7 +9,7 @@ The injection context is available in these situations:
* In the initializer for fields of such classes.
* In the factory function specified for `useFactory` of a `Provider` or an `@Injectable`.
* In the `factory` function specified for an `InjectionToken`.
* Within a stack frame that is run in a injection context.
* Within a stack frame that is run in an injection context.
Knowing when your are in an injection context, will allow you to use the [`inject`](api/core/inject) function to inject instances.
@@ -60,4 +60,4 @@ Calling [`inject`](api/core/inject) or calling `assertInInjectionContext` outsid
@reviewed 2023-04-11
@reviewed 2023-04-11
+7
View File
@@ -124,6 +124,13 @@ v16 - v19
| `@angular/platform-browser` | [`BrowserModule.withServerTransition`](api/platform-browser/BrowserModule#withservertransition) | v16 | v18 |
| `@angular/platform-browser` | [`makeStateKey`, `StateKey` and `TransferState`](#platform-browser), symbols were moved to `@angular/core` | v16 | v18 |
### Deprecated features that can be removed in v19 or later
| Area | API or Feature | Deprecated in | May be removed in |
|:--- |:--- |:--- |:--- |
| `@angular/core` | `PACKAGE_ROOT_URL` | v17 | v19 |
### Deprecated features with no planned removal version
| Area | API or Feature | Deprecated in | May be removed in |
@@ -58,7 +58,7 @@ The `<ng-template>` element is a good choice for dynamic components because it d
Take a closer look at the methods in `ad-banner.component.ts`.
`AdBannerComponent` takes an array of `AdItem` objects as input, which ultimately comes from `AdService`.
`AdItem` objects specify the type of component to load and any data to bind to the component.`AdService` returns the actual ads making up the ad campaign.
`AdItem` objects specify the type of component to load and any data to bind to the component. `AdService` returns the actual ads making up the ad campaign.
Passing an array of components to `AdBannerComponent` allows for a dynamic list of ads without static elements in the template.
+11 -8
View File
@@ -12,7 +12,7 @@ For the sample application that this page describes, see the <live-example></liv
A custom element extends HTML by allowing you to define a tag whose content is created and controlled by JavaScript code.
The browser maintains a `CustomElementRegistry` of defined custom elements, which maps an instantiable JavaScript class to an HTML tag.
The `@angular/elements` package exports a `createCustomElement()` API that provides a bridge from Angular's component interface and change detection functionality to the built-in DOM API.
The `@angular/elements` package exports a `createCustomElement()` API function that provides a bridge from Angular's component interface and change detection functionality to the built-in DOM API.
Transforming a component to a custom element makes all of the required Angular infrastructure available to the browser.
Creating a custom element is simple and straightforward, and automatically connects your component-defined view with change detection and data binding, mapping Angular functionality to the corresponding built-in HTML equivalents.
@@ -33,7 +33,7 @@ Once a custom element is added to the DOM for any page, it looks and behaves lik
| | Details |
|:--- |:--- |
| Easy dynamic content in an Angular application | Transforming a component to a custom element provides a straightforward path to creating dynamic HTML content in your Angular application. HTML content that you add directly to the DOM in an Angular application is normally displayed without Angular processing, unless you define a *dynamic component*, adding your own code to connect the HTML tag to your application data, and participate in change detection. With a custom element, all of that wiring is taken care of automatically. |
| Content-rich applications | If you have a content-rich application, such as the Angular app that presents this documentation, custom elements let you give your content providers sophisticated Angular functionality without requiring knowledge of Angular. For example, an Angular guide like this one is added directly to the DOM by the Angular navigation tools, but can include special elements like `<code-snippet>` that perform complex operations. All you need to tell your content provider is the syntax of your custom element. They don't need to know anything about Angular, or anything about your component's data structures or implementation. |
| Content-rich applications | If you have a content-rich application, such as the Angular application described in this guide, custom elements let you give your content providers sophisticated Angular functionality without requiring knowledge of Angular. For example, an Angular guide like this one is added directly to the DOM by the Angular navigation tools, but can include special elements like `<code-snippet>` that perform complex operations. All you need to tell your content provider is the syntax of your custom element. They don't need to know anything about Angular, or anything about your component's data structures or implementation. |
### How it works
@@ -92,8 +92,8 @@ Component properties and logic maps directly into HTML attributes and the browse
For example, for a component with `@Input('myInputProp') inputProp`, the corresponding custom element defines an attribute `my-input-prop`.
* Component outputs are dispatched as HTML [Custom Events](https://developer.mozilla.org/docs/Web/API/CustomEvent), with the name of the custom event matching the output name.
For example, for a component with `@Output() valueChanged = new EventEmitter()`, the corresponding custom element dispatches events with the name "valueChanged", and the emitted data is stored on the event's `detail` property.
If you provide an alias, that value is used; for example, `@Output('myClick') clicks = new EventEmitter<string>();` results in dispatch events with the name "myClick".
For example, for a component with `@Output() valueChanged = new EventEmitter()`, the corresponding custom element dispatches events with the name `valueChanged`, and the emitted data is stored on the event's `detail` property.
If you provide an alias, that value will be used instead; for example, `@Output('myClick') clicks = new EventEmitter<string>();` results in dispatch events with the name `myClick`.
For more information, see Web Component documentation for [Creating custom events](https://developer.mozilla.org/docs/Web/Guide/Events/Creating_and_triggering_events#Creating_custom_events).
@@ -124,14 +124,17 @@ npm install @angular/elements --save
Previously, when you wanted to add a component to an application at runtime, you had to define a *dynamic component*, and then you would have to load it, attach it to an element in the DOM, and wire up all of the dependencies, change detection, and event handling, as described in [Dynamic Component Loader](guide/dynamic-component-loader).
Using an Angular custom element makes the process much simpler and more transparent, by providing all of the infrastructure and framework automatically &mdash;all you have to do is define the kind of event handling you want.
\(You do still have to exclude the component from compilation, if you are not going to use it in your application.\)
<div class="alert is-helpful">
You do still have to exclude the component from compilation, if you are not going to use it in your application.
</div>
The following Popup Service example application defines a component that you can either load dynamically or convert to a custom element.
| Files | Details |
|:--- |:--- |
| `popup.component.ts` | Defines a simple pop-up element that displays an input message, with some animation and styling. |
| `popup.service.ts` | Creates an injectable service that provides two different ways to invoke the `PopupComponent`; as a dynamic component, or as a custom element Notice how much more setup is required for the dynamic-loading method. |
| `popup.service.ts` | Creates an injectable service that provides two different ways to invoke the `PopupComponent`; as a dynamic component, or as a custom element. Notice how much more setup is required for the dynamic-loading method. |
| `app.module.ts` | Adds the `PopupComponent` in the module's `declarations` list. |
| `app.component.ts` | Defines the application's root component, which uses the `PopupService` to add the pop-up to the DOM at run time. When the application runs, the root component's constructor converts `PopupComponent` to a custom element. |
@@ -159,7 +162,7 @@ Additionally, these custom elements will have a property for each input of the c
For example, our `popup-element` has a `message` property of type `string`.
There are a few options if you want to get correct types for your custom elements.
Assume you create a `my-dialog` custom element based on the following component:
Assuming you create a `my-dialog` custom element based on the following component:
<code-example format="typescript" language="typescript">
@@ -216,4 +219,4 @@ document.querySelector('my-other-element') //--&gt; NgElement &amp; WithPropert
<!-- end links -->
@reviewed 2022-02-28
@reviewed 2023-04-27
+1 -1
View File
@@ -97,7 +97,7 @@ Angular components, templates, and styles go here.
| `app/app.component.html` | Defines the HTML template associated with the root `AppComponent`. |
| `app/app.component.css` | Defines the base CSS stylesheet for the root `AppComponent`. |
| `app/app.component.spec.ts` | Defines a unit test for the root `AppComponent`. |
| `app/app.module.ts` | Defines the root module, named `AppModule`, that tells Angular how to assemble the application. Initially declares only the `AppComponent`. As you add more components to the app, they must be declared here.<br><br>_Only generated when using the `--standalone` option._ |
| `app/app.module.ts` | Defines the root module, named `AppModule`, that tells Angular how to assemble the application. Initially declares only the `AppComponent`. As you add more components to the app, they must be declared here.<br><br>_This file is not generated when using the `--standalone` option._ |
### Application configuration files
@@ -232,7 +232,7 @@ For example, in the following `SelfComponent`, notice the injected `LeafService`
<code-example header="src/app/self-no-data/self-no-data.component.ts" path="resolution-modifiers/src/app/self-no-data/self-no-data.component.ts" region="self-no-data-component"></code-example>
In this example, there is a parent provider and injecting the service will return the value, however, injecting the service with `@Self()` and `@Optional()` will return `null` because `@Self()` tells the injector to stop searching in the current host element.
In this example, there is a parent provider and injecting the service will return the value, however, injecting the service with `@Self()` and `@Optional()` will return `null` because `@Self()` tells the injector to only search in the current host element.
Another example shows the component class with a provider for `FlowerService`.
In this case, the injector looks no further than the current `ElementInjector` because it finds the `FlowerService` and returns the tulip <code>&#x1F337;</code>.
+8 -1
View File
@@ -125,6 +125,13 @@ If you choose to set this setting in your tsconfig, we recommend to set it only
</div>
<a id="cdn-configuration"></a>
### CDN Optimizations
Many CDNs offer a feature that will try to optimize your rendered application by stripping all nodes from the rendered DOM that it thinks are unnecessary, which includes comment nodes. Comment nodes are an essential part of Angular's functioning and are critical for hydration to work. You will need to disable this CDN feature in order to ensure your application loads and hydrates.
If CDN optimization is enabled and you have hydration enabled, when you attempt to load the page you will encounter error [NG0507](https://angular.io/errors/NG0507). If you see this error, you should go and disable the CDN optimization.
### Custom or Noop Zone.js are not yet supported
Hydration relies on a signal from Zone.js when it becomes stable inside an application, so that Angular can start the serialization process on the server or post-hydration cleanup on the client to remove DOM nodes that remained unclaimed.
@@ -184,4 +191,4 @@ re-rendering those components from scratch.
There are a number of third party libraries that depend on DOM manipulation to be able to render. D3 charts is a prime example. These libraries worked without hydration, but they may cause DOM mismatch errors when hydration is enabled. For now, if you encounter DOM mismatch errors using one of these libraries, you can add the `ngSkipHydration` attribute to the component that renders using that library.
@reviewed 2023-06-21
@reviewed 2023-08-14
+1 -1
View File
@@ -220,7 +220,7 @@ You may want to have images displayed at varying widths on differently-sized scr
The `sizes` attribute in the above example says "I expect this image to be 100 percent of the screen width on devices under 768px wide. Otherwise, I expect it to be 50 percent of the screen width.
For additional information about the `sizes` attribute, see [web.dev](https://web.dev/learn/design/responsive-images/#sizes) or [mdn](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes).
For additional information about the `sizes` attribute, see [web.dev](https://web.dev/learn/design/responsive-images/#sizes) or [MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes).
## Configuring an image loader for `NgOptimizedImage`
+1 -8
View File
@@ -75,13 +75,6 @@ ng new customer-app --routing
This creates an application called `customer-app` and the `--routing` flag generates a file called `app-routing.module.ts`. This is one of the files you need for setting up lazy loading for your feature module.
Navigate into the project by issuing the command `cd customer-app`.
<div class="alert is-helpful">
The `--routing` option requires Angular CLI version 8.1 or higher.
See [Keeping Up to Date](guide/updating).
</div>
### Create a feature module with routing
Next, you need a feature module with a component to route to.
@@ -251,7 +244,7 @@ For more information, see the [`forRoot()` pattern](guide/singleton-services#for
## Preloading
Preloading improves UX by loading parts of your application in the background.
You can preload modules, standalone components or component data.
You can preload modules, standalone components or component data.
### Preloading modules and standalone components
+91
View File
@@ -138,6 +138,97 @@ data$ = http.get('...').pipe(takeUntilDestroyed());
By default, `takeUntilDestroyed` must be called in an [injection context](/guide/dependency-injection-context) so that it can access `DestroyRef`. If an injection context isn't available, you can explicitly provide a `DestroyRef`.
## Reading and writing the DOM
Sometimes it's necessary to use browser-only APIs to manually read or write the DOM. This can be challenging to do with the [lifecycle events](#lifecycle-event-sequence) above, as they will also run during [server-side rendering and pre-rendering](guide/glossary#server-side-rendering). For this purpose, Angular provides `afterRender` and `afterNextRender`. These functions can be used unconditionally, but will only have an effect on the browser. Both functions accept a callback that will run after the next [change detection](/guide/glossary#change-detection) cycle (including any nested cycles) has completed.
<div class="alert is-important">
`afterRender` and `afterNextRender` are available for [developer preview](/guide/releases#developer-preview). They are ready for you to try, but they might change before they are stable.
</div>
| Function | Purpose | Timing |
| ------ | ------- | ------ |
| `afterNextRender` | Perform one-time initialization, or observe a single, specific change to the DOM. <br /> <div class="alert is-helpful">As a rule of thumb, you should use `afterRender` instead if you need to manually read or write any layout data such as size or location.</div> See details in [One-time initialization](#one-time-initialization) in this document. | _Once_ after the next change detection cycle. |
| `afterRender` | Synchronize state with the DOM. See details in [Handling synchronization](#handling-synchronization) in this document. | After _every_ change detection cycle that follows. |
### One-time initialization
Generally, you will want to use `afterNextRender` to perform any one-time initialization, such as for a third-party library, or for browser-only APIs.
```ts
@Component({
selector: 'my-chart-cmp',
template: `<div #chart>{{ ... }}</div>`,
})
export class MyChartCmp {
@ViewChild('chart') chartRef: ElementRef;
chart: MyChart|null;
constructor() {
afterNextRender(() => {
this.chart = new MyChart(this.chartRef.nativeElement);
});
}
}
```
Instead of attempting to recreate their behaviors with `afterRender`, you should prefer to use built-in browser APIs like `ResizeObserver` and `IntersectionObserver` wherever possible. You can use `afterNextRender` to safely initialize such APIs on the browser only.
```ts
@Component({
selector: 'my-cmp',
template: `<span #content>{{ ... }}</span>`,
})
export class MyComponent {
resizeObserver: ResizeObserver|null = null;
@ViewChild('content') contentRef: ElementRef;
constructor() {
afterNextRender(() => {
this.resizeObserver = new ResizeObserver(() => {
console.log('Content was resized');
});
this.resizeObserver.observe(this.contentRef.nativeElement);
});
}
ngOnDestroy() {
this.resizeObserver?.disconnect();
this.resizeObserver = null;
}
}
```
<div class="alert is-important">
As a rule of thumb, `afterNextRender` should be used to observe _discrete_ changes to the DOM, such as element creation or deletion. For manually reading or writing data that tends to change frequently, such as size or location, you should generally prefer to use `afterRender` instead.
</div>
### Handling synchronization
As an escape hatch for when the browser does not provide a better API to do so, you can use `afterRender` to perform any additional read or writes to the DOM every time Angular finishes mutating it.
```ts
@Component({
selector: 'my-cmp',
template: `<span #content>{{ ... }}</span>`,
})
export class MyComponent {
@ViewChild('content') contentRef: ElementRef;
constructor() {
afterRender(() => {
const elem = this.contentRef.nativeElement;
console.log(`content position: (${elem.offsetLeft}, ${elem.offsetTop})`);
});
}
}
```
## General examples
The following examples demonstrate the call sequence and relative frequency of the various lifecycle events, and how the hooks can be used separately or together for components and directives.
+18 -6
View File
@@ -21,7 +21,7 @@ Start with the top-level component that hosts the view, and nest animations in t
To enable routing transition animation, do the following:
1. Import the routing module into the application and create a routing configuration that defines the possible routes.
1. Create a routing configuration that defines the possible routes. For NgModule based applications, this will include creating a `RouterModule` and adding it to the main `AppModule`.
1. Add a router outlet to tell the Angular router where to place the activated components in the DOM.
1. Define the animation.
@@ -37,15 +37,27 @@ Implement a router transition animation that slides in the new view to the right
## Route configuration
To begin, configure a set of routes using methods available in the `RouterModule` class.
This route configuration tells the router how to navigate.
To begin, configure a set of routes. This route configuration tells the router how to navigate.
Use the `RouterModule.forRoot` method to define a set of routes.
Also, add `RouterModule` to the `imports` array of the main module, `AppModule`.
- Create an array called `routes` in `app.routes.ts` to define a set of routes.
- Add the routes to the `provideRouter` function in the providers array in `app.config.ts`.
```ts
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes)
]
};
```
<div class="alert is-helpful">
**NOTE**: <br />
For `NgModule` based applications:
Use the `RouterModule.forRoot` method to define a set of routes.
Also, add `RouterModule` to the `imports` array of the main module, `AppModule`.
Use the `RouterModule.forRoot` method in the root module, `AppModule`, to register top-level application routes and providers.
For feature modules, call the `RouterModule.forChild` method instead.
@@ -53,7 +65,7 @@ For feature modules, call the `RouterModule.forChild` method instead.
The following configuration defines the possible routes for the application.
<code-example header="src/app/app.module.ts" path="animations/src/app/app.module.ts" region="route-animation-data"></code-example>
<code-example header="src/app/app.routes.ts" path="animations/src/app/app.routes.ts" region="route-animation-data"></code-example>
The `home` and `about` paths are associated with the `HomeComponent` and `AboutComponent` views.
The route configuration tells the Angular router to instantiate the `HomeComponent` and `AboutComponent` views when the navigation matches the corresponding path.
+23
View File
@@ -1623,6 +1623,29 @@ This time, the value of `'popup'` is `null`.
That's not a route, but it is a legitimate value.
Setting the popup `RouterOutlet` to `null` clears the outlet and removes the secondary popup route from the current URL.
<div class="alert is-critical">
**Note:** All commands in the array passed to `Router.navigate()` target a _specific segment_ in the `UrlTree`.
We specify the parent of the `ActivatedRoute` as the `relativeTo` option because we want to remove `'popup'` from the segment which holds its reference.
It's important to always be aware of which segments the commands will be applied to.
</div>
<div class="alert is-helpful">
When `relativeTo` is not provided to the `Router.navigate()` method, the commands are processed starting at the root.
We could omit the `relativeTo` option in this particular example because the `'popup'` outlet appears at the root level of the configuration.
</div>
<div class="alert is-helpful">
If you want to close an outlet which appears at any segment depth, you could accomplish
this by creating a `UrlTree` from the current URL, recursively clearing segment `children` matching the outlet name, and finally
calling `Router.navigateByUrl()` with the `root` segment of the current `UrlTree`.
</div>
<a id="guards"></a>
<a id="milestone-5-route-guards"></a>
@@ -88,7 +88,7 @@ In addition, using the `onActionClick` property on the `data` object, you can ti
{"action": "foo", "title": "Open new tab"},
{"action": "bar", "title": "Focus last"},
{"action": "baz", "title": "Navigate last"},
{"action": "qux", "title": "Send request in the background"}
{"action": "qux", "title": "Send request in the background"},
{"action": "other", "title": "Just notify existing clients"}
],
"data": {
+1 -1
View File
@@ -47,7 +47,7 @@ Congratulations, your application has been converted to standalone 🎉. These a
* Find and remove any remaining `NgModule` declarations: since the ["Remove unnecessary NgModules" step](#remove-unnecessary-ngmodules) cannot remove all modules automatically, you may have to remove the remaining declarations manually.
* Run the project's unit tests and fix any failures.
* Run any code formatters, if the project uses automatic formatting.
* Run any linters in your project and fix new warnings. Some linters support a `--fix` flag that may resolve so warnings automatically.
* Run any linters in your project and fix new warnings. Some linters support a `--fix` flag that may resolve some of your warnings automatically.
## Migration modes
The migration has the following modes:
+1 -1
View File
@@ -150,7 +150,7 @@ To test your Angular CLI application in Continuous integration \(CI\) run the fo
<code-example format="shell" language="shell">
ng test --no-watch --no-progress
ng test --no-watch --no-progress --browsers=ChromeHeadless
</code-example>
+1 -1
View File
@@ -10,7 +10,7 @@ covers [Angular versions under active support](guide/releases#actively-supported
| Angular | Node.js | TypeScript | RxJS |
|--------------------|--------------------------------------|----------------|--------------------|
| 16.1.x | ^16.14.0 \|\| ^18.10.0 | >=4.9.3 <5.2.0 | ^6.5.3 \|\| ^7.4.0 |
| 16.1.x \|\| 16.2.x | ^16.14.0 \|\| ^18.10.0 | >=4.9.3 <5.2.0 | ^6.5.3 \|\| ^7.4.0 |
| 16.0.x | ^16.14.0 \|\| ^18.10.0 | >=4.9.3 <5.1.0 | ^6.5.3 \|\| ^7.4.0 |
| 15.1.x \|\| 15.2.x | ^14.20.0 \|\| ^16.13.0 \|\| ^18.10.0 | >=4.8.2 <5.0.0 | ^6.5.3 \|\| ^7.4.0 |
| 15.0.x | ^14.20.0 \|\| ^16.13.0 \|\| ^18.10.0 | ~4.8.2 | ^6.5.3 \|\| ^7.4.0 |
+1 -1
View File
@@ -86,7 +86,7 @@ To clarify how changes are detected and values updated, consider the following c
value = v;
// call detectChange manually
detectChange();
}, 100);
});
// Example 5: some other asynchronous APIs
document.getElementById('canvas').toBlob(blob =&gt; {
+2 -2
View File
@@ -17,9 +17,9 @@
</h1>
<div class="cta-button-container">
<p class="cta-link">
<div class="cta-link">
<a class="button hero-cta no-print" href="quick-start">Try Angular</a>
</p>
</div>
</div>
</div>
+5 -6
View File
@@ -112,12 +112,6 @@
"logo": "",
"title": "NgRuAir",
"url": "https://github.com/ngRuAir/ngruair"
},
"ngxp": {
"desc": "Weekly technical-adjacent podcast by Brooke Avery & Erik Slack. Don't just code in Angular, come enjoy the Angular Experience!",
"logo": "",
"title": "Angular Experience (NgXP)",
"url": "https://ngxp.show"
}
}
}
@@ -574,6 +568,11 @@
"desc": "NGX Cookie Service is an Angular Library that can be used to read, set and delete browser cookies",
"title": "NGX Cookie Service",
"url": "https://github.com/stevermeister/ngx-cookie-service"
},
"flowbite": {
"desc": "Open-source UI component library built with the utility-classes from Tailwind CSS and with official support for Angular.",
"title": "Flowbite",
"url": "https://flowbite.com/docs/getting-started/angular/"
}
}
}
+1 -1
View File
@@ -1525,7 +1525,7 @@
{
"url": "https://github.com/angular/angular/issues",
"title": "Report Issues",
"tooltip": "Post issues and suggestions on github."
"tooltip": "Post issues and suggestions on GitHub."
},
{
"url": "https://github.com/angular/code-of-conduct/blob/main/CODE_OF_CONDUCT.md",
@@ -20,10 +20,7 @@ This tutorial creates a `HeroService` that all application classes can use to ge
Instead of creating that service with the [`new` keyword](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/new), use the [*dependency injection*](guide/dependency-injection) that Angular supports to inject it into the `HeroesComponent` constructor.
Services are a great way to share information among classes that *don't know each other*.
Create a `MessageService` next and inject it in these two places.
* Inject in `HeroService`, which uses the service to send a message
* Inject in `MessagesComponent`, which displays that message, and also displays the ID when the user clicks a hero
Create a `HeroService` next and inject it in the `HeroesComponent`, to provide hero data.
## Create the `HeroService`
+14 -14
View File
@@ -61,33 +61,33 @@
},
"private": true,
"dependencies": {
"@angular/animations": "16.2.0-next.3",
"@angular/animations": "16.2.0",
"@angular/cdk": "16.2.0-next.4",
"@angular/common": "16.2.0-next.3",
"@angular/compiler": "16.2.0-next.3",
"@angular/core": "16.2.0-next.3",
"@angular/elements": "16.2.0-next.3",
"@angular/forms": "16.2.0-next.3",
"@angular/common": "16.2.0",
"@angular/compiler": "16.2.0",
"@angular/core": "16.2.0",
"@angular/elements": "16.2.0",
"@angular/forms": "16.2.0",
"@angular/material": "16.2.0-next.4",
"@angular/platform-browser": "16.2.0-next.3",
"@angular/platform-browser-dynamic": "16.2.0-next.3",
"@angular/router": "16.2.0-next.3",
"@angular/service-worker": "16.2.0-next.3",
"@angular/platform-browser": "16.2.0",
"@angular/platform-browser-dynamic": "16.2.0",
"@angular/router": "16.2.0",
"@angular/service-worker": "16.2.0",
"rxjs": "~7.8.0",
"safevalues": "^0.4.2",
"tslib": "^2.3.0",
"zone.js": "~0.13.0"
},
"devDependencies": {
"@angular-devkit/architect-cli": "0.1602.0-next.3",
"@angular-devkit/build-angular": "16.2.0-next.3",
"@angular-devkit/architect-cli": "0.1602.0",
"@angular-devkit/build-angular": "16.2.0",
"@angular-eslint/builder": "16.0.3",
"@angular-eslint/eslint-plugin": "16.0.3",
"@angular-eslint/eslint-plugin-template": "16.0.3",
"@angular-eslint/template-parser": "^16.0.3",
"@angular/build-tooling": "https://github.com/angular/dev-infra-private-build-tooling-builds.git#4463309193594fc8b23090c89c7f34178320681c",
"@angular/cli": "16.2.0-next.3",
"@angular/compiler-cli": "16.2.0-next.3",
"@angular/cli": "16.2.0",
"@angular/compiler-cli": "16.2.0",
"@bazel/bazelisk": "^1.7.5",
"@bazel/buildozer": "^6.0.0",
"@bazel/ibazel": "^0.16.2",
+5 -2
View File
@@ -3,8 +3,11 @@
and runs a fast dgeni build on any changed files.
*/
import {createRequire} from 'node:module';
import spawn from 'cross-spawn';
import watchr from '../tools/transforms/authors-package/watchr.js';
import {watch} from '../tools/transforms/authors-package/watchr.js';
const require = createRequire(import.meta.url);
const architectCli = require.resolve('@angular-devkit/architect-cli/bin/architect');
const serve = spawn(
@@ -30,4 +33,4 @@ serve.on('close', (code) => {
process.exit(1);
});
watchr.watch(true);
watch(true);
+1
View File
@@ -5,6 +5,7 @@ set -eu -o pipefail
readonly thisDir=$(cd $(dirname $0); pwd)
readonly parentDir=$(dirname $thisDir)
readonly target=${1:-aio}
readonly PROJECT_ROOT=$(realpath "$(dirname ${thisDir})/..")
# Track payload size functions
source ../scripts/ci/payload-size.sh
+4 -4
View File
@@ -11,8 +11,8 @@
<header>
<mat-toolbar #appToolbar color="primary" class="app-toolbar no-print" [class.transitioning]="isTransitioning">
<mat-toolbar-row class="notification-container">
<aio-notification notificationId="survey-january-2023" expirationDate="2023-02-15" [dismissOnContentClick]="true" (dismissed)="notificationDismissed()">
<a href="https://goo.gle/angular-devsat-q1-2023">
<aio-notification notificationId="survey-august-2023" expirationDate="2023-11-02" [dismissOnContentClick]="true" (dismissed)="notificationDismissed()">
<a href="https://goo.gle/angular-devsat-q3-2023">
<mat-icon class="icon" svgIcon="insert_comment" aria-label="Announcement"></mat-icon>
<span class="message">Help Angular by taking a <strong>quick survey</strong>!</span>
<span class="action-button">Go to survey</span>
@@ -31,10 +31,10 @@
<aio-search-box class="search-container" #searchBox (onSearch)="doSearch($event)" (onFocus)="doSearch($event, true)"></aio-search-box>
<aio-theme-toggle #themeToggle></aio-theme-toggle>
<div #externalIcons class="toolbar-external-icons-container">
<a mat-icon-button href="https://twitter.com/angular" title="Twitter" aria-label="Angular on twitter">
<a mat-icon-button href="https://twitter.com/angular" title="Twitter" aria-label="Angular on Twitter">
<mat-icon svgIcon="logos:twitter"></mat-icon>
</a>
<a mat-icon-button href="https://github.com/angular/angular" title="GitHub" aria-label="Angular on github">
<a mat-icon-button href="https://github.com/angular/angular" title="GitHub" aria-label="Angular on GitHub">
<mat-icon svgIcon="logos:github"></mat-icon>
</a>
<a mat-icon-button href="https://youtube.com/angular" title="YouTube" aria-label="Angular on YouTube">
@@ -12,8 +12,8 @@ import { Logger } from 'app/shared/logger.service';
import { fromOuterHTML } from 'app/shared/security';
import { TocService } from 'app/shared/toc.service';
import {
MockTitle, MockTocService, ObservableWithSubscriptionSpies,
TestDocViewerComponent, TestModule, TestParentComponent, MockElementsLoader
MockTitle, MockTocService, ObservableWithSubscriptionSpies,
TestDocViewerComponent, TestModule, TestParentComponent, MockElementsLoader, MockMeta
} from 'testing/doc-viewer-utils';
import { MockLogger } from 'testing/logger.service';
import { DocViewerComponent, NO_ANIMATIONS } from './doc-viewer.component';
@@ -110,7 +110,7 @@ describe('DocViewerComponent', () => {
});
});
describe('#prepareTitleAndToc()', () => {
describe('#prepareMetadataAndToc()', () => {
const EMPTY_DOC = '';
const DOC_WITHOUT_H1 = 'Some content';
const DOC_WITH_H1 = '<h1>Features</h1>Some content';
@@ -124,12 +124,12 @@ describe('DocViewerComponent', () => {
let targetEl: HTMLElement;
const getTocEl = () => targetEl.querySelector('aio-toc');
const doPrepareTitleAndToc = (contents: string, docId = '') => {
const prepareMetadataAndToc = (contents: string, docId = '') => {
targetEl.innerHTML = contents;
return docViewer.prepareTitleAndToc(targetEl, docId);
return docViewer.prepareMetadataAndToc(targetEl, docId);
};
const doAddTitleAndToc = (contents: string, docId = '') => {
const addTitleAndToc = doPrepareTitleAndToc(contents, docId);
const addTitleAndToc = prepareMetadataAndToc(contents, docId);
return addTitleAndToc();
};
@@ -144,7 +144,7 @@ describe('DocViewerComponent', () => {
afterEach(() => document.body.removeChild(targetEl));
it('should return a function for doing the actual work', () => {
const addTitleAndToc = doPrepareTitleAndToc(DOC_WITH_H1);
const addTitleAndToc = prepareMetadataAndToc(DOC_WITH_H1);
expect(getTocEl()).toBeTruthy();
expect(titleService.setTitle).not.toHaveBeenCalled();
@@ -158,6 +158,39 @@ describe('DocViewerComponent', () => {
expect(tocService.genToc).toHaveBeenCalledTimes(1);
});
it('should set the meta description to the first paragraph text', () => {
const contentWithParagraphTags = `
<h1>NgIf</h1>
<p>NgIf is a directive</p>
<p>It hides and shows content</p>`;
const meta = TestBed.inject(Meta) as unknown as MockMeta;
const metaElement = document.createElement('meta');
metaElement.setAttribute('name', 'Description');
(meta as any).getTag = jasmine.createSpy('Meta#getTag').and.returnValue(metaElement);
doAddTitleAndToc(contentWithParagraphTags);
expect(metaElement?.getAttribute('content')).toBe('NgIf is a directive');
});
it('should set the meta description when there is an empty paragraph', () => {
const contentWithParagraphTags = `
<h1>NgIf</h1>
<p><a></a></p>
<p>NgIf is a directive</p>
<p>It hides and shows content</p>`;
const meta = TestBed.inject(Meta) as unknown as MockMeta;
const metaElement = document.createElement('meta');
metaElement.setAttribute('name', 'Description');
(meta as any).getTag = jasmine.createSpy('Meta#getTag').and.returnValue(metaElement);
doAddTitleAndToc(contentWithParagraphTags);
expect(metaElement?.getAttribute('content')).toBe('NgIf is a directive');
});
describe('(title)', () => {
it('should set the title if there is an `<h1>` heading', () => {
doAddTitleAndToc(DOC_WITH_H1);
@@ -216,7 +249,7 @@ describe('DocViewerComponent', () => {
describe('(ToC)', () => {
describe('needed', () => {
it('should add an embedded ToC element if there is an `<h1>` heading', () => {
doPrepareTitleAndToc(DOC_WITH_H1);
prepareMetadataAndToc(DOC_WITH_H1);
const tocEl = getTocEl();
expect(tocEl).toBeTruthy();
@@ -224,7 +257,7 @@ describe('DocViewerComponent', () => {
});
it('should not add a second ToC element if there a hard coded one in place', () => {
doPrepareTitleAndToc(DOC_WITH_EMBEDDED_TOC);
prepareMetadataAndToc(DOC_WITH_EMBEDDED_TOC);
expect(targetEl.querySelectorAll('aio-toc').length).toEqual(1);
});
});
@@ -232,23 +265,23 @@ describe('DocViewerComponent', () => {
describe('not needed', () => {
it('should not add a ToC element if there is a `.no-toc` `<h1>` heading', () => {
doPrepareTitleAndToc(DOC_WITH_NO_TOC_H1);
prepareMetadataAndToc(DOC_WITH_NO_TOC_H1);
expect(getTocEl()).toBeFalsy();
});
it('should not add a ToC element if there is no `<h1>` heading', () => {
doPrepareTitleAndToc(DOC_WITHOUT_H1);
prepareMetadataAndToc(DOC_WITHOUT_H1);
expect(getTocEl()).toBeFalsy();
doPrepareTitleAndToc(EMPTY_DOC);
prepareMetadataAndToc(EMPTY_DOC);
expect(getTocEl()).toBeFalsy();
});
it('should remove ToC a hard coded one', () => {
doPrepareTitleAndToc(DOC_WITH_EMBEDDED_TOC_WITHOUT_H1);
prepareMetadataAndToc(DOC_WITH_EMBEDDED_TOC_WITHOUT_H1);
expect(getTocEl()).toBeFalsy();
doPrepareTitleAndToc(DOC_WITH_EMBEDDED_TOC_WITH_NO_TOC_H1);
prepareMetadataAndToc(DOC_WITH_EMBEDDED_TOC_WITH_NO_TOC_H1);
expect(getTocEl()).toBeFalsy();
});
});
@@ -297,7 +330,7 @@ describe('DocViewerComponent', () => {
});
describe('#render()', () => {
let prepareTitleAndTocSpy: jasmine.Spy;
let prepareMetadataAndTocSpy: jasmine.Spy;
let swapViewsSpy: jasmine.Spy;
let loadElementsSpy: jasmine.Spy;
@@ -307,7 +340,7 @@ describe('DocViewerComponent', () => {
beforeEach(() => {
const elementsLoader = TestBed.inject(ElementsLoader) as Partial<ElementsLoader> as MockElementsLoader;
loadElementsSpy = elementsLoader.loadContainedCustomElements.and.callFake(() => of(undefined));
prepareTitleAndTocSpy = spyOn(docViewer, 'prepareTitleAndToc');
prepareMetadataAndTocSpy = spyOn(docViewer, 'prepareMetadataAndToc');
swapViewsSpy = spyOn(docViewer, 'swapViews').and.callFake(() => of(undefined));
});
@@ -341,20 +374,20 @@ describe('DocViewerComponent', () => {
});
it('should prepare the title and ToC (before embedding components)', async () => {
prepareTitleAndTocSpy.and.callFake((targetEl: HTMLElement, docId: string) => {
prepareMetadataAndTocSpy.and.callFake((targetEl: HTMLElement, docId: string) => {
expect(targetEl.innerHTML).toBe('Some content');
expect(docId).toBe('foo');
});
await doRender(htmlEscape('Some content'), 'foo');
expect(prepareTitleAndTocSpy).toHaveBeenCalledTimes(1);
expect(prepareTitleAndTocSpy).toHaveBeenCalledBefore(loadElementsSpy);
expect(prepareMetadataAndTocSpy).toHaveBeenCalledTimes(1);
expect(prepareMetadataAndTocSpy).toHaveBeenCalledBefore(loadElementsSpy);
});
it('should set the title and ToC (after the content has been set)', async () => {
const addTitleAndTocSpy = jasmine.createSpy('addTitleAndToc');
prepareTitleAndTocSpy.and.returnValue(addTitleAndTocSpy);
prepareMetadataAndTocSpy.and.returnValue(addTitleAndTocSpy);
addTitleAndTocSpy.and.callFake(() => expect(docViewerEl.textContent).toBe('Foo content'));
await doRender(htmlEscape('Foo content'));
@@ -433,7 +466,7 @@ describe('DocViewerComponent', () => {
it('should pass the `addTitleAndToc` callback', async () => {
const addTitleAndTocSpy = jasmine.createSpy('addTitleAndToc');
prepareTitleAndTocSpy.and.returnValue(addTitleAndTocSpy);
prepareMetadataAndTocSpy.and.returnValue(addTitleAndTocSpy);
const el = document.createElement('div');
await doRender(fromOuterHTML(el));
@@ -465,16 +498,16 @@ describe('DocViewerComponent', () => {
logger = TestBed.inject(Logger) as unknown as MockLogger;
});
it('when `prepareTitleAndTocSpy()` fails', async () => {
const error = Error('Typical `prepareTitleAndToc()` error');
prepareTitleAndTocSpy.and.callFake(() => {
it('when `prepareMetadataAndTocSpy()` fails', async () => {
const error = Error('Typical `prepareMetadataAndToc()` error');
prepareMetadataAndTocSpy.and.callFake(() => {
expect(docViewer.nextViewContainer.innerHTML).not.toBe('');
throw error;
});
await doRender(htmlEscape('Some content'), 'foo');
expect(prepareTitleAndTocSpy).toHaveBeenCalledTimes(1);
expect(prepareMetadataAndTocSpy).toHaveBeenCalledTimes(1);
expect(swapViewsSpy).not.toHaveBeenCalled();
expect(docViewer.nextViewContainer.innerHTML).toBe('');
expect(logger.output.error).toEqual([
@@ -493,7 +526,7 @@ describe('DocViewerComponent', () => {
await doRender(htmlEscape('Some content'), 'bar');
expect(prepareTitleAndTocSpy).toHaveBeenCalledTimes(1);
expect(prepareMetadataAndTocSpy).toHaveBeenCalledTimes(1);
expect(loadElementsSpy).toHaveBeenCalledTimes(1);
expect(swapViewsSpy).not.toHaveBeenCalled();
expect(docViewer.nextViewContainer.innerHTML).toBe('');
@@ -512,7 +545,7 @@ describe('DocViewerComponent', () => {
await doRender(htmlEscape('Some content'), 'qux');
expect(prepareTitleAndTocSpy).toHaveBeenCalledTimes(1);
expect(prepareMetadataAndTocSpy).toHaveBeenCalledTimes(1);
expect(swapViewsSpy).toHaveBeenCalledTimes(1);
expect(docViewer.nextViewContainer.innerHTML).toBe('');
expect(logger.output.error).toEqual([
@@ -87,10 +87,10 @@ export class DocViewerComponent implements OnDestroy {
}
/**
* Prepare for setting the window title and ToC.
* Prepare for setting the page metadata (title + description) and table-of-contents.
* Return a function to actually set them.
*/
protected prepareTitleAndToc(targetElem: HTMLElement, docId: string): () => void {
prepareMetadataAndToc(targetElem: HTMLElement, docId: string): () => void {
const titleEl = targetElem.querySelector('h1');
const needsTitle = !!titleEl && !/no-?title/i.test(titleEl.className);
const needsToc = !!titleEl && !/no-?toc/i.test(titleEl.className);
@@ -123,6 +123,21 @@ export class DocViewerComponent implements OnDestroy {
}
this.titleService.setTitle(title ? `Angular - ${title}` : 'Angular');
// Set the page description via the existing `<meta name="Description">` tag.
// Updating the page description provides information for internet search indexers.
// Pull the next from the first paragraph element that has text since the docs
// processing pipeline sometimes results in pages where the first paragraph tag
// is empty.
const paragraphs = targetElem.querySelectorAll('p');
const firstParagraph =
Array.from(paragraphs).find(p => p.textContent?.trim());
const firstParagraphText = firstParagraph?.textContent?.trim();
if (firstParagraphText) {
const descriptionMeta = this.metaService.getTag('name="Description"');
descriptionMeta?.setAttribute('content', firstParagraphText);
}
};
}
@@ -144,7 +159,7 @@ export class DocViewerComponent implements OnDestroy {
this.nextViewContainer.innerHTML = unwrapHtml(doc.contents) as string;
}
}),
tap(() => addTitleAndToc = this.prepareTitleAndToc(this.nextViewContainer, doc.id)),
tap(() => addTitleAndToc = this.prepareMetadataAndToc(this.nextViewContainer, doc.id)),
switchMap(() => this.elementsLoader.loadContainedCustomElements(this.nextViewContainer)),
tap(() => this.docReady.emit()),
switchMap(() => this.swapViews(addTitleAndToc)),
@@ -1,14 +1,14 @@
<div class="search-results" [ngSwitch]="searchState">
<ng-container *ngSwitchCase="'in-progress'">
<p class="no-results">Searching ...</p>
<p class="no-results">Searching...</p>
</ng-container>
<ng-container *ngSwitchCase="'results-found'">
<h2 class="visually-hidden">Search Results</h2>
<div class="search-area" *ngFor="let area of searchAreas">
<h3 class="search-section-header">{{area.name}} ({{area.pages.length + area.priorityPages.length}})</h3>
<ul class="priority-pages" >
<ul class="priority-pages">
<li class="search-page" *ngFor="let page of area.priorityPages">
<a class="search-result-item" href="{{ page.path }}" (click)="onResultSelected(page, $event)">
<span class="symbol {{page.type}}" *ngIf="area.name === 'api'"></span>
@@ -287,9 +287,9 @@ describe('SearchResultsComponent', () => {
});
});
it('should display "Searching ..." while waiting for search results', () => {
it('should display "Searching..." while waiting for search results', () => {
fixture.detectChanges();
expect(getText()).toContain('Searching ...');
expect(getText()).toContain('Searching...');
});
it('should not display default links while searching', () => {
@@ -1,8 +1,4 @@
.contribute-container {
h2 {
margin: 0;
}
.card-section {
justify-content: space-between;
+1 -1
View File
@@ -21,7 +21,7 @@ export class TestDocViewerComponent extends DocViewerComponent {
override nextViewContainer: HTMLElement;
// Only used for type-casting; the actual implementation is irrelevant.
override prepareTitleAndToc(_targetElem: HTMLElement, _docId: string): () => void {
override prepareMetadataAndToc(_targetElem: HTMLElement, _docId: string): () => void {
return null as any;
}
@@ -20,7 +20,7 @@ function next(error) {
}
}
function watch() {
export function watch() {
console.log('============================================================================');
console.log('Started watching files in:');
console.log(' - ', config.CONTENTS_PATH);
@@ -32,4 +32,3 @@ function watch() {
watchr.open(config.API_SOURCE_PATH, listener, next);
}
exports.watch = watch;
@@ -42,6 +42,7 @@
</code-example>
</td>
</tr>
{%- if option.description or option.usageNotes %}
<tr>
<td>
{%- if option.description %}
@@ -53,6 +54,7 @@
{% endif %}
</td>
</tr>
{% endif %}
</tbody>
</table>
{% endfor %}
+364 -327
View File
File diff suppressed because it is too large Load Diff
@@ -88,7 +88,7 @@ const queryMap: {[query in QueryType]: Query} =
return map;
}, {} as {[query in QueryType]: Query});
const queryRe = new RegExp(`!?\s*(${QueryType.Duration}|${QueryType.Source})$`, 'g');
const queryRe = new RegExp(`!?s*(${QueryType.Duration}|${QueryType.Source})$`, 'g');
type Predicate = true|false;
type QueryAST = [Predicate, QueryType, QueryArguments];
+1
View File
@@ -51,6 +51,7 @@ new as of May 2017 and not very stable yet.
- Test package in node: `yarn test packages/core/test:test`
- Test package in karma: `yarn test packages/core/test:test_web`
- Test all packages: `yarn test packages/...`
- Test angular.io app locally: `yarn test //aio/... --config=aio_local_deps`
**Note**: The ellipsis in the last command above are not meant to be substituted by a package name, but
are used by Bazel as a wildcard to execute all tests in the specified path. To execute all the tests for a
+2
View File
@@ -31,6 +31,8 @@ following products on your development machine:
* [Yarn](https://yarnpkg.com) (version specified in the engines field of [`package.json`](../package.json)) which is used to install dependencies.
* On Windows: [MSYS2](https://www.msys2.org/) which is used by Bazel. Follow the [instructions](https://bazel.build/install/windows#installing-compilers-and-language-runtimes)
* Optional: [Java](https://openjdk.java.net/) version 7 or higher than required by [Closure Compiler](https://developers.google.com/closure/compiler). Most developers will not need this. Java is required for running some integration tests.
## Getting the Sources
+2
View File
@@ -617,6 +617,8 @@ export class NgOptimizedImage implements OnInit, OnChanges, OnDestroy {
// (undocumented)
static ngAcceptInputType_height: unknown;
// (undocumented)
static ngAcceptInputType_ngSrc: string | i1_2.SafeValue;
// (undocumented)
static ngAcceptInputType_priority: unknown;
// (undocumented)
static ngAcceptInputType_width: unknown;
+2
View File
@@ -85,6 +85,8 @@ export const enum RuntimeErrorCode {
// (undocumented)
MISSING_REQUIRED_INJECTABLE_IN_BOOTSTRAP = 402,
// (undocumented)
MISSING_SSR_CONTENT_INTEGRITY_MARKER = -507,
// (undocumented)
MISSING_ZONEJS = 908,
// (undocumented)
MULTIPLE_COMPONENTS_MATCH = -300,
+1 -1
View File
@@ -1126,7 +1126,7 @@ export interface OutputDecorator {
new (alias?: string): any;
}
// @public
// @public @deprecated
export const PACKAGE_ROOT_URL: InjectionToken<string>;
// @public
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<!-- Prevent the browser from requesting any favicon. -->
<link rel="icon" href="data:," />
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<body>
<h2>Params</h2>
<form>
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<!-- Prevent the browser from requesting any favicon. -->
<link rel="icon" href="data:," />
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<!-- Prevent the browser from requesting any favicon. -->
<link rel="icon" href="data:," />
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<!-- Prevent the browser from requesting any favicon. -->
<link rel="icon" href="data:," />
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<!-- Prevent the browser from requesting any favicon. -->
<link rel="icon" href="data:," />
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<!-- Prevent the browser from requesting any favicon. -->
<link rel="icon" href="data:," />
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<!-- Prevent the browser from requesting any favicon. -->
<link rel="icon" href="data:," />
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<!-- Prevent the browser from requesting any favicon. -->
<link rel="icon" href="data:," />
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "16.2.0-next.4",
"version": "16.2.3",
"private": true,
"description": "Angular - a web framework for modern web apps",
"homepage": "https://github.com/angular/angular",
@@ -18,7 +18,7 @@ import {AnimationDslVisitor} from './animation_dsl_visitor';
import {parseTransitionExpr} from './animation_transition_expr';
const SELF_TOKEN = ':self';
const SELF_TOKEN_REGEX = new RegExp(`\s*${SELF_TOKEN}\s*,?`, 'g');
const SELF_TOKEN_REGEX = new RegExp(`s*${SELF_TOKEN}s*,?`, 'g');
/*
* [Validation]
@@ -1,27 +0,0 @@
/**
* @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.io/license
*/
/**
* DOMAnimation represents the Animation Web API.
*
* It is an external API by the browser, and must thus use "declare interface",
* to prevent renaming by Closure Compiler.
*
* @see https://developer.mozilla.org/de/docs/Web/API/Animation
*/
export declare interface DOMAnimation {
cancel(): void;
play(): void;
pause(): void;
finish(): void;
onfinish: Function;
position: number;
currentTime: number;
addEventListener(eventName: string, handler: (event: any) => any): any;
dispatchEvent(eventName: string): any;
}

Some files were not shown because too many files have changed in this diff Show More